在模板化函数中键入const引用的推导

时间:2015-02-19 14:21:31

标签: c++ templates template-function universal-reference

下面我有一个名为ProxyCall的模板函数,它接受一个对象,一个成员函数及其参数。它只是将调用转发给成员函数。

我希望能够在不使用模板限定符的情况下调用该函数(想象大量此类调用具有多个参数)。当我尝试传递const引用参数时,类型推导主要起作用,但编译器(msvc和gcc 4.9)都是barf。

#include <string>

struct Widget {
    void f(const std::string& s, bool b) {}
};


template<typename T, typename... Args>
void ProxyCall(T &obj, void(T::*method)(Args...), Args&&... args) {
    (obj.*method)(std::forward<Args>(args)...);
}


int main(int argc, char* argv[])
{
    Widget w;
    std::string s;

    ProxyCall<Widget, const std::string&, bool>(w, &Widget::f, s, true); // OK
    ProxyCall(w, &Widget::f, (const std::string&)s, true); // also OK

    ProxyCall(w, &Widget::f, s, true); // ERROR: template parameter is ambiguous
    return 0;
}

我的问题是:如何修改上面的代码,以便编译器自动推导出类型,而无需借助显式模板限定符或显式转换。考虑到编译器已经知道Widget :: f。

的签名中的确切参数类型,这似乎应该是可能的

1 个答案:

答案 0 :(得分:3)

template<typename T, typename... Args>
void ProxyCall(T &obj, void(T::*method)(Args...), Args&&... args) {
    (obj.*method)(std::forward<Args>(args)...);
}
Args的第二个参数和尾随参数推导出

ProxyCall 在第三种情况下,由于s不是constArgs会推断为[std::string&, bool](请回想一下参考折叠和转发参考的规则)。但是,成员函数签名明显不同。因此,在Args中推导出第一种类型的两种不同类型,这导致演绎失败。

相反,要使参数类型和参数独立 - 并转发object参数,以便引用ref-qualifiers:

template<typename T, typename F, typename... Args>
void ProxyCall(T&& obj, F method, Args&&... args) {
    (std::forward<T>(obj).*method)(std::forward<Args>(args)...);
}