我打开了关于转发引用的here帖子,这是(希望)MCVE代码:
#include <functional>
#include <vector>
using namespace std;
struct MultiMemoizator {
template <typename ReturnType, typename... Args>
ReturnType callFunction(std::function<ReturnType(Args...)> memFunc, Args&&... args) {
}
};
typedef vector<double> vecD;
vecD sort_vec (const vecD& vec) {
return vec;
}
int main()
{
vecD vec;
std::function<vecD(const vecD&)> sortFunc(sort_vec);
MultiMemoizator mem;
mem.callFunction<vecD, vecD>(sortFunc, vec);
}
由于这不是整个代码,我可能需要根据答案添加额外的代码。
无论如何,正如this回答中所建议的那样,此版本无法转发引用,因为Args
不会被推断出来。
所以我的问题是:是否有可能使这段代码“转发参考”?
答案 0 :(得分:2)
为了完善你的论点,你需要推断出类型。您可以通过单独推导函数的参数和函数的参数来完成此操作:
template <typename ReturnType, typename... FunArgs, typename... Args>
ReturnType callFunction(std::function<ReturnType(FunArgs...)> memFunc,
Args&&... args)
{
//...
}
然后你可以在没有模板参数的情况下调用callFunction
并推断出所有内容:
mem.callFunction(sortFunc, vec);
答案 1 :(得分:0)
我将在为什么你的代码无法编译(即使没有明确的模板参数)的情况下添加一些关于@TartanLlama答案的详细信息,还有为什么(在我看来)你的代码是危险
在下文中,我将仅使用简单类型T
而不是参数包Args...
,因为它更容易解释,并且不会改变含义。
首先,让我们举一个比你更简单的例子:
template <typename T>
void f (T&&);
现在,让我们从各种来源实现f
,让我们假设有以下变量:
std::string s;
const std::string cs;
...然后:
f(s); // instanciate f<std::string&>
f(cs); // instanciate f<const std::string&>
f(std::string()); // instanciate f<std::string&&>
你应该想知道:为什么第一个实例f<std::string&>
而不是f<std::string>
?,但标准告诉你(§14.8.2.1#3 [ temp.deduct.call] 强>):
如果P是转发引用且参数是a 左值,类型“左值引用A”用于代替A进行类型扣除。
现在,让我们的例子复杂一点:
template <typename T>
struct A {};
template <typename T>
void f (A<T>, T&&);
一个实例:
std::string s;
A<std::string> as;
f(as, s);
以上相当于你的例子,将无法编译,但为什么......?好吧,如上所述,当你有一个左值时,T&&
的推断类型是T&
,而不是T
,因此类型推导失败{ {1}}因为编译器期待A<T>
而您正在提供A<std::string&>
。
所以现在我们知道我们必须做以下事情:
A<std::string>
好的,现在,这应该是好的:
A<std::string&> ars;
A<std::string const&> acrs;
f(ars, s); // good
f(acrs, cs); // good
但它不是......因为当A<std::string&&> arrs;
f(arrs, std::string());
被推断为右值引用时,T
只是T
,所以编译器期待T
。
所以这就是问题:你要给一个方法提供一个 rvalue ,然后将它转发给一个期望 lvalue 的函数。这没错,但可能不是你想象的那样。
第一种可能性是强制第一个参数的类型,而不管A<std::string>
的推断类型,例如:
T
但请注意:
template <typename T>
void f (A<typename std::remove_reference<T>::type>, T&&);
。const
的用处。第二种可能性(警告:我不知道这是否是标准的!)是在末尾移动第一个参数,然后从T&&
中推断出类型:
t
现在,template <typename T>
void f (T &&t, A<decltype(std::forward<T>(t))>);
的推断类型与T
的预期类型完全匹配。
不幸的是,我不知道如何使用可变参数模板进行上述工作......