将成员函数指针传递给带有可变参数的MFP的函数时,类型不匹配



我有一个模板函数,它接受一个指针,该指针指向任何类型的成员函数,具有任意数量的参数(但强制执行一些规则-它必须是空的,最后一个参数必须是指针):

class Foo {
public:
    Foo() {}
    template<typename T, typename Out, typename ... In>
    void foo(T *obj, void(T::*func)(In ..., Out*)) {
        ...
    }
    ...
};

当我试图调用该函数时,我得到一个类型不匹配错误:

class Bar {
public:
    Bar() {}
    void bar(int in, bool *out) {
        ...
    }
};
int main()
{
   Foo foo;
   Bar bar;
   foo.foo<Bar, bool, int>(&bar, &Bar::bar);
   ...
}
错误:

test.cpp: In function 'int main()':
test.cpp:41:44: error: no matching function to call to 'Foo::foo(Bar*, void (Bar::*)(int, bool*))'
    foo.foo<Bar, bool, int>(&bar, &Bar::bar);
                                           ^
test.cpp:24:10: note: candidate: template<class T, class Out, class ... In> void Foo::foo(T*, void (T::*)(In ..., Out*))
    void foo(T *obj, void(T::*func)(In ..., Out*))
         ^
test.cpp:24:10: note    template argument deduction/substitution failed:
test.cpp:41:44: note    mismatched types 'bool*' and 'int'
    foo.foo<Bar, bool, int>(&bar, &Bar::bar);
                                           ^

有趣的是,当我使In为简单类型而不是参数包时,它会编译并正确工作。在我看来,如果编译器没有在某个地方扩展包,并尝试将第二个参数(bool*)匹配到第一个参数(int),而不是第二个。

不确定为什么您的示例不起作用,但可能的解决方案是编写一个trait来检查参数包中的最后一个类型是否为指针,然后std::enable_if:

template <typename... Ts>
struct last_is_pointer : std::false_type{};
template <typename T1, typename T2, typename... Ts>
struct last_is_pointer<T1, T2, Ts...> : last_is_pointer<T2,Ts...>{};
template <typename T>
struct last_is_pointer<T> : std::is_pointer<T>{};
class Foo {
public:
    Foo() {}
    template<typename T, typename... Args>
    typename std::enable_if<last_is_pointer<Args...>::value>::type
    foo(T *obj, void(T::*func)(Args...)) {
    }
};

然后不指定任何模板参数,直接调用:

foo.foo(&bar, &Bar::bar);

现场演示

在对编译器进行了更多的研究之后,我发现了一个模板包装器形式的简单解决方案。显然,gcc和clang在Out*之前扩展In ...包在类型别名(usingtypedef)中没有问题,只有当它是函数定义的一部分时才会遇到问题。

namespace detail {
    template<typename T, typename Out, typename ... In>
    struct funcHelper {
        using type = void(T::*)(In ..., Out*);
    };
}
class Foo {
public:
    Foo() {}
    template<typename T, typename Out, typename ... In>
    void foo(T *obj, typename detail::funcHelper<T, Out, In ...>::type func) {
        ...
    }
    ...
};

class Bar {
public:
    Bar() {}
    void bar(int in, bool *out) {
        ...
    }
};
int main()
{
   Foo foo;
   Bar bar;
   foo.foo<Bar, bool, int>(&bar, &Bar::bar);
   ...
}

最新更新