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

时间:2014-11-18 12:59:09

标签: 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;
}

如代码中所述,我在函数接受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); ^ 。我得到以下编译错误:

{{1}}

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

1 个答案:

答案 0 :(得分:14)

您调用功能模板的方式,模板参数包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)...);    
}