完善的函数转发构建函数列表类 [英] Perfect forwarding of functions to build a function list class
问题描述
//函数列表类
模板< p>类... F>
struct function_list
{
template< class ... G>
constexpr function_list(G&& g)noexcept
:_f {std :: forward< G>(g)...}
{
}
std :: tuple< / * F ... OR F&& ... * /> _F;
};
//函数列表生成器
模板< class ... F,class R = / *我们可以在这里计算返回类型吗? * />
constexpr R make_function_list(F&& ... f)
{
return function_list<
/ * decltype(std :: forward< F>(f))...
* OR F ...
* OR F&& ...
* />(标准::向前< f是氟烃基;(F)...);
}
我希望这些函数能够完美转发(不管它们是否为函数指针,函子,lambdas ...)。但我不完全理解 编辑: 但我不完全理解 通过一个例子很容易理解。 如果(0): 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 $ c
当运算符()
function_list
(这里没有显示)不保证在同一个语句上被调用?
模板< class ... F>
constexpr function_list< F ...> make_function_list(F& amp; ... f)
{
return function_list< F& amp;>(std :: forward< F>(f)...);
}
std :: forward
和通用引用背后发生的所有类型推演。
模板< typename T>
void f(T&);
{
std :: tuple< T> {}; //(0)
std :: tuple< T&&> {}; // <1>
-
T
推断为T对于 rvalues
, -
T
被推断为T&
for 左值。 -
T
推断为T&&
for rvalues -
T
T&
为左值。 可以看到,两者之间的唯一区别是如何推导出 rvalues 。关于 -
x
总是一个左值 >。 -
x
被转换为T&&
ifT
推断为T
。 -
x
保留一个左值,否则。
1):
std :: forward $>的
c $ c>,这就是它的作用:
模板< typename T>
void g(T&& amp;);
模板< typename T>
void f(T& x)
{
g(x)//(0)
g(std :: forward< T>(x)); // <1>
如果(0):
对于(1):
通过查看 std :: forward
基本上保留了 x
的类型类别。 T
被推断出来。
code> std :: tuple< F ...> 或
std :: tuple< F&& ...>
我认为在你的情况下应该是 std :: tuple< F ...> ,因为您要存储左值引用或值。
的std ::元组< F&安培;& amp; ...>
会存储左值引用或右值引用 - 这会导致悬空引用在临时情况下。
是否可以推导出返回类型<$ c
是的,它只是在模板参数列表中$ c> R
function_list< F的> 。
模板< class ... F,class R = function_list< F ...>>
constexpr R make_function_list(F& ... f)
{
return function_list< F ...>(std :: forward< F>(f)...) ;
$ / code>
你甚至不需要 R
模板参数。
模板< class ... F>
constexpr function_list< F ...> make_function_list(F& ... f)
{
return function_list< F ...>(std :: forward< F>(f)...);
}
<在制造商中,function_list
模板参数应该是:decltype(std :: forward< F>(f)...)
,F
或F&< / code>
function_list
应该取F ...
as一个模板参数,用于回答开头列出的原因(即避免对临时对象的悬挂引用)。
它仍然需要
std :: forward< F>(f)...
作为它的参数来允许 rvaluesfunction_list
的元组)。Consider the following code that build a class storing functions.
// 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)...); }
I would like these functions to be perfectly forwarded (regardless of whether they are function pointers, functors, lambdas...). But I don't exactly understand all the type deduction happening behind
std::forward
and universal references. In the code above, I have three questions:
- Should
_f
be of typestd::tuple<F...>
orstd::tuple<F&&...>
(and why?)- Is it possible to deduce the return type
R
in the template parameter list (because doing it manually instead ofauto/decltype(auto)
would be helpful to understand what is going on)- In the maker, what the
function_list
template argument should be:decltype(std::forward<F>(f)...)
,F
, orF&&...
(and why?)Note: the constructor of
function_list
is not meant to be called directly, insteadmake_function_list
is doing the job.EDIT: Is this case safe, when the
operator()
offunction_list
(not shown here) is not guaranted to be called on the same statement?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.It's quite simple to understand via an example.
template <typename T> void f(T&&) { std::tuple<T>{}; // (0) std::tuple<T&&>{}; // (1) }
In the case of (0):
T
is deduced asT
for rvaluesT
is deduced asT&
for lvalues.In the case of (1):
T
is deduced asT&&
for rvaluesT
is deduced asT&
for lvalues.As you can see, the only difference between two is how rvalues are deduced.
Regarding
std::forward
, this is what it does:template <typename T> void g(T&&); template <typename T> void f(T&& x) { g(x) // (0) g(std::forward<T>(x)); // (1) }
In the case of (0):
x
is always an lvalue.In the case of (1):
x
is casted toT&&
ifT
is deduced asT
.
x
stays an lvalue otherwise.
std::forward
basically retains the type category ofx
by looking at howT
was deduced.
Should _f be of type
std::tuple<F...>
orstd::tuple<F&&...>
I think that in your case it should be
std::tuple<F...>
, as you want to store either lvalue references or values.
std::tuple<F&&...>
would store either lvalue references or rvalue references - that would lead to dangling references in the case of temporaries.
Is it possible to deduce the return type
R
in the template parameter listYes, it is just
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)...); }
You don't even need the
R
template parameter.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
should takeF...
as a template parameter for the reasons listed at the beginning of this answer (i.e. avoiding dangling references to temporaries).It should still take
std::forward<F>(f)...
as its arguments to allow rvalues to be forwarded as such (i.e. moving rvalues intofunction_list
's tuple).这篇关于完善的函数转发构建函数列表类的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!