模板函数中 const 引用的类型推导
Type deduction of const references in templated functions
下面我有一个名为 ProxyCall 的模板函数,它接受一个对象、一个成员函数及其参数。它只是将调用转发给成员函数。
我希望能够在不使用模板限定符的情况下调用该函数(想象一下大量带有多个参数的此类调用)。类型推导大部分都有效,但是当我尝试像示例中那样传递 const 引用参数时,编译器(msvc 和 gcc 4.9)会感到厌烦。
#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.
的签名中知道确切的参数类型,这似乎应该是可能的
template<typename T, typename... Args>
void ProxyCall(T &obj, void(T::*method)(Args...), Args&&... args) {
(obj.*method)(std::forward<Args>(args)...);
}
Args
是从 ProxyCall
.
的第二个参数和尾随参数推导出来的
在您的第三种情况下,由于 s
不是 const
,因此 Args
被推断为 [std::string&, bool]
(回想参考折叠和转发参考的规则)。但是,成员函数签名明显不同。因此Args
中的第一种推导了两种不同的类型,导致推导失败。
相反,为了引用限定符,使参数类型和参数独立 - 并转发对象参数:
template<typename T, typename F, typename... Args>
void ProxyCall(T&& obj, F method, Args&&... args) {
(std::forward<T>(obj).*method)(std::forward<Args>(args)...);
}
下面我有一个名为 ProxyCall 的模板函数,它接受一个对象、一个成员函数及其参数。它只是将调用转发给成员函数。
我希望能够在不使用模板限定符的情况下调用该函数(想象一下大量带有多个参数的此类调用)。类型推导大部分都有效,但是当我尝试像示例中那样传递 const 引用参数时,编译器(msvc 和 gcc 4.9)会感到厌烦。
#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.
的签名中知道确切的参数类型,这似乎应该是可能的template<typename T, typename... Args>
void ProxyCall(T &obj, void(T::*method)(Args...), Args&&... args) {
(obj.*method)(std::forward<Args>(args)...);
}
Args
是从 ProxyCall
.
的第二个参数和尾随参数推导出来的
在您的第三种情况下,由于 s
不是 const
,因此 Args
被推断为 [std::string&, bool]
(回想参考折叠和转发参考的规则)。但是,成员函数签名明显不同。因此Args
中的第一种推导了两种不同的类型,导致推导失败。
相反,为了引用限定符,使参数类型和参数独立 - 并转发对象参数:
template<typename T, typename F, typename... Args>
void ProxyCall(T&& obj, F method, Args&&... args) {
(std::forward<T>(obj).*method)(std::forward<Args>(args)...);
}