使用可变参数模板的参数包扣除不一致

jef*_*eon 8 c++ templates variadic-templates

我有以下C++ 11示例,其中我有一个call使用可变参数模板接受和调用泛型类方法的函数:

#include <utility>

template <typename T, typename R, typename... Args>
R call(R (T::*fn)(Args...), T *t, Args&&... args) {
    return ((*t).*fn)(std::forward<Args>(args)...);    
}

class Calculator {
    public:
    int add(const int& a, const int& b) {
        return a + b;
    }
};

int main() {
    Calculator *calculator = new Calculator();
    int* a = new int(2);    
    int* b = new int(4);

    // compiles
    int res1 = calculator->add(*a, *b);    

    // does not compile!
    int res2 = call<Calculator>(&Calculator::add,calculator, *a, *b);    

    return 0;
}
Run Code Online (Sandbox Code Playgroud)

正如在代码中评论的那样,我无法int在函数接受时传递const int,而在方向调用中我可以.我得到以下编译错误:

error: no matching function for call to ‘call(int (Calculator::*)(const int&, const int&), Calculator*&, int&, int&)’
     int res2 = call<Calculator>(&Calculator::add,calculator, *a, *b);    
                                                                    ^

inconsistent parameter pack deduction with ‘const int&’ and ‘int&’
     int res2 = call<Calculator>(&Calculator::add,calculator, *a, *b);    
                                                                    ^
Run Code Online (Sandbox Code Playgroud)

与常规执行相比,C++可变参数模板是否会强制执行更严格的类型检查?我正在使用带有C++ 11的g ++ 4.8.1.

T.C*_*.C. 15

您调用函数模板的方式,模板参数包Args将从两个来源推断:

  • 成员函数指针的类型 - int (Calculator::*)(const int&, const int&)
  • 参数的实际类型(*a, *b)您为函数参数包传递 -int &, int &

为了使推论成功,推导出的结果必须完全匹配.他们显然没有.

这对于可变参数模板来说并不新鲜或特殊.如果您尝试这样做,则会遇到相同的问题std::max(1, 1.5)- 编译器int从一个参数推断出另一个参数double,并且由于两个冲突导致演绎失败.

最简单的修复可能需要两包:

template <typename T, typename R, typename... Args1, typename... Args2>
R call(R (T::*fn)(Args1...), T *t, Args2&&... args) {
    return ((*t).*fn)(std::forward<Args2>(args)...);    
}
Run Code Online (Sandbox Code Playgroud)