C++20 返回非类型可变模板引用元组

huangapple go评论56阅读模式
英文:

C++20 Returning Non-type Variadic Template Tuple of References

问题

Currently using g++11.3.0, C++20.

This is a follow up from a previous query.

I have a function foo that takes an arbitrary number of template arguments and returns a tuple that contains a value for each template argument. However, the function currently returns a tuple of l-values. I would like to return a tuple of l-value references. I've tried changing the return type to std::tuple<Args&...> and using std::tie() instead of std::make_tuple(), but it gives me the error:

error: no matching function for call to 'tie'

The lambda in the function actually returns a non-local variable with the respective data type, so the line return Args(); is just there as a substitution to provide compilable code for this post.

template <typename ...Args>
std::tuple<Args...> foo()
{
    return std::make_tuple([] ()
    {
        // Do some stuff....
        // Return non-local l-value....

        return Args();
    }()...);
}
英文:

Currently using g++11.3.0, C++20.

This is a follow up from a previous query.

I have a function foo that takes an arbitrary number of template arguments and returns a tuple that contains a value for each template argument. However, the function currently returns a tuple of l-values. I would like to return a tuple of l-value references. I've tried changing the return type to std::tuple&lt;Args&amp;...&gt; and using std::tie() instead of std::make_tuple(), but gives me the error:

error: no matching function for call to &#39;tie&#39;

The lambda in the function actually returns a non-local variable with the respective data type, so the line return Args(); is just there as a substitution to provide compilable code for this post.

template &lt;typename ...Args&gt;
std::tuple&lt;Args...&gt; foo()
{
    return std::make_tuple([] ()
    {
        // Do some stuff....
        // Return non-local l-value....

        return Args();
    }()...);
}

答案1

得分: 1

不要有别的内容

英文:

A lambda without specified return value always returns by-value, not by-reference. Specifically it returns with a return type of auto by default. So your call to the lambda never produces a lvalue, always a prvalue. std::tie then fails, because it accepts only lvalues.

If you want to have the lambda return a lvalue reference, you need to specify its return type. I wouldn't make it specifically a lvalue reference though. You can have it deduce the appropriate value category automatically with decltype(auto):

[] () -&gt; decltype(auto)
{
    // Do some stuff....
    // Return non-local l-value....

    return Args();
}()

(However, Args() is a prvalue, not a lvalue, so this will still deduce to a non-reference type. If you actually want to have the lambda return a lvalue reference, then actually give the return statement a lvalue as operand.)

Alternatively you can specify Args&amp; as the return type of the lambda explicitly.

After that, you can use std::tie or alternatively std::forward_as_tuple. The latter will correctly deduce whether the references should be lvalue references or rvalue references automatically, while std::tie assumes lvalue references and will fail otherwise. Typically it is desirable that the value category is deduced, although in your situation it might be a potential source of error since it would have caused UB instead of a compilation error with your wrong return type on the lambda.

Then you can also use auto as return type for foo, so that the automatically deduced value category applies, but that is a matter of style.


On a side note, if your lambdas have side effects, note that the order in which the lambdas will be evaluated is indeterminate. You can not rely on any particular ordering.

huangapple
  • 本文由 发表于 2023年2月6日 09:19:03
  • 转载请务必保留本文链接:https://go.coder-hub.com/75356607.html
匿名

发表评论

匿名网友

:?: :razz: :sad: :evil: :!: :smile: :oops: :grin: :eek: :shock: :???: :cool: :lol: :mad: :twisted: :roll: :wink: :idea: :arrow: :neutral: :cry: :mrgreen:

确定