【问题标题】:Inconsistent parameter pack deduction with variadic templates可变参数模板的参数包推导不一致
【发布时间】:2014-11-18 12:59:08
【问题描述】:

我有以下 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;
}

正如代码中所述,当函数接受const int 时,我无法传递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);    
                                                                    ^

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

【问题讨论】:

  • 也许你会更喜欢 Clang 的错误:注意:候选模板被忽略:推断参数“Args”的冲突类型( vs. )
  • 那么这是否意味着在使用可变参数模板时类型必须完全匹配?
  • 这意味着你不能为同一个模板参数推导出不同的类型,因为编译器不知道你想要哪个。您总是可以跳过显式函数捕获,只使用一个可调用的对象参数:template &lt;typename F, typename T, typename... Args&gt; auto call(F f, T *t, Args&amp;&amp;... args) { return (t-&gt;*f)(std::forward&lt;Args&gt;(args)...); }
  • @chris:使用这种方法,我的调用方会是什么样子?我应该将什么作为F 类型的参数传递?
  • 只需删除显式模板参数。

标签: c++ templates variadic-templates


【解决方案1】:

你调用函数模板的方式,模板参数包Args会从两个来源推导出来:

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

要使推导成功,推导的结果必须完全匹配。他们显然没有。

这对于可变参数模板来说并不新鲜或特殊。如果您尝试执行 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)...);    
}

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 2013-09-14
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2012-10-26
    • 1970-01-01
    • 2020-06-05
    • 1970-01-01
    相关资源
    最近更新 更多