简体   繁体   English

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

[英]Type mismatch when passing member function pointer to a function that takes MFP with variadic arguments

I have a template function that takes pointer to a member function of any type with any amount of arguments (but enforces some rules - it has to be void and the last argument has to be a pointer): 我有一个模板函数,该函数使用指向具有任何数量参数的任何类型的成员函数的指针(但强制执行一些规则-它必须为空,最后一个参数必须为指针):

class Foo {
public:
    Foo() {}

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

When I try to invoke the function, I get a type mismatch error: 当我尝试调用该函数时,出现类型不匹配错误:

class Bar {
public:
    Bar() {}
    void bar(int in, bool *out) {
        ...
    }
};

int main()
{
   Foo foo;
   Bar bar;

   foo.foo<Bar, bool, int>(&bar, &Bar::bar);
   ...
}

Error: 错误:

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);
                                           ^

The interesting things is that when I make In a simple type instead of parameter pack then it compiles and works correctly. 有趣的事情是,当我做In一个简单的类型,而不是参数包然后编译并正常工作。 This seems to me like if the compiler did not expand the pack somewhere and try to match the second argument ( bool* ) to the first argument ( int ) instead of the second one. 在我看来,这似乎是如果编译器没有将包扩展到某个地方并尝试将第二个参数( bool* )与第一个参数( int )而不是第二个参数匹配。

Not sure exactly why your example doesn't work, but a possible solution is to write a trait to check if the last type in a parameter pack is a pointer, then std::enable_if on that: 不确定为什么您的示例不起作用,但是一个可能的解决方案是编写一个特征以检查参数包中的最后一个类型是否是指针,然后在其上输入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...)) {

    }
};

Then simply call this without specifying any template arguments: 然后,只需调用它而不指定任何模板参数即可:

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

Live Demo 现场演示

After a bit more of messing around with compilers, I found a simple workaround in a form of a template wrapper. 在对编译器进行了更多处理之后,我发现了一种简单的解决方法,以模板包装器的形式存在。 Apparently gcc and clang have no problem with expanding the In ... pack before Out* in a type alias ( using or typedef ) and only struggle when it's part of a function definition. 显然,gcc和clang在类型别名( usingtypedef )中在Out*之前扩展In ...包时没有问题,并且仅当它在函数定义中时才挣扎。

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);
   ...
}

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM