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

时间:2015-09-01 14:07:54

标签: c++ c++11

我有一个模板函数,它使用任意数量的参数获取任何类型的成员函数(但强制执行一些规则 - 它必须为void,最后一个参数必须是指针):

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)匹配而不是第二个参数(<{p}}。

2 个答案:

答案 0 :(得分:0)

不确定为什么你的例子不起作用,但一个可能的解决方案是写一个特征来检查参数包中的最后一个类型是否是一个指针,然后是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);

Live Demo

答案 1 :(得分:0)

在对编译器进行了一些讨论之后,我发现了一种模板包装器形式的简单解决方法。显然gcc和clang在类型别名(Out*using)中扩展typedef之前的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); ... } 包没有问题,只有在它的一部分时才会遇到困难功能定义。

angular.forEach($scope.list, function (item) {
          alert(item);
  });