考虑以下构建类存储函数的代码。
// Function list class
template <class... F>
struct function_list
{
template <class... G>
constexpr function_list(G&&... g) noexcept
: _f{std::forward<G>(g)...}
{
}
std::tuple</* F... OR F&&... */> _f;
};
// Function list maker
template <class... F, class R = /* Can we compute the return type here? */>
constexpr R make_function_list(F&&... f)
{
return function_list<
/* decltype(std::forward<F>(f))...
* OR F...
* OR F&&...
*/>(std::forward<F>(f)...);
}
我希望这些函数能够完美转发(不管它们是函数指针、仿函数、lambdas...)。但我并不完全理解 std::forward
背后发生的所有类型推导。和通用引用。在上面的代码中,我有三个问题:
- 应该
_f
类型为std::tuple<F...>
或std::tuple<F&&...>
(为什么?) - 是否可以推导出返回类型
R
在模板参数列表中(因为手动而不是auto/decltype(auto)
将有助于理解正在发生的事情) - 在制造商中,
function_list
是什么模板参数应为:decltype(std::forward<F>(f)...)
,F
, 或F&&...
(为什么?)
注:function_list
的构造函数并不意味着直接调用,而是 make_function_list
正在做这项工作。
编辑:
这种情况安全吗,当operator()
的 function_list
(此处未显示)不保证在同一语句中被调用?
template <class... F>
constexpr function_list<F...> make_function_list(F&&... f)
{
return function_list<F&&...>(std::forward<F>(f)...);
}
最佳答案
But I don't exactly understand all the type deduction happening behind
std::forward
and universal references.
通过一个例子就很容易理解了。
template <typename T>
void f(T&&)
{
std::tuple<T>{}; // (0)
std::tuple<T&&>{}; // (1)
}
对于(0):
-
T
推导为T
对于右值 -
T
推导为T&
对于左值。
对于(1):
-
T
推导为T&&
对于右值 -
T
推导为T&
对于左值。
如您所见,两者之间的唯一区别是右值的推导方式。
关于 std::forward
,这就是它的作用:
template <typename T>
void g(T&&);
template <typename T>
void f(T&& x)
{
g(x) // (0)
g(std::forward<T>(x)); // (1)
}
对于(0):
-
x
始终是一个左值。
对于(1):
x
被转换到T&&
如果T
推导为T
.x
否则保持左值。
std::forward
基本保留了x
的类型分类通过查看如何 T
被推导出来。
Should _f be of type
std::tuple<F...>
orstd::tuple<F&&...>
我认为你的情况应该是 std::tuple<F...>
,因为您要存储左值引用 或值。
std::tuple<F&&...>
将存储左值引用 或右值引用 - 在临时对象的情况下会导致悬空引用。
Is it possible to deduce the return type
R
in the template parameter list
是的,就是function_list<F...>
.
template <class... F, class R = function_list<F...>>
constexpr R make_function_list(F&&... f)
{
return function_list<F...>(std::forward<F>(f)...);
}
你甚至不需要 R
模板参数。
template <class... F>
constexpr function_list<F...> make_function_list(F&&... f)
{
return function_list<F...>(std::forward<F>(f)...);
}
In the maker, what the
function_list
template argument should be:decltype(std::forward<F>(f)...)
,F
, orF&&...
function_list
应该采取 F...
出于本答案开头列出的原因作为模板参数(即避免对临时对象的悬空引用)。
它仍然需要 std::forward<F>(f)...
作为允许右值被转发的参数(即将右值移动到function_list
的元组中)。
关于c++ - 功能完美转发构建功能列表类,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/42032755/