有没有一种方法可以禁用临时对象参数的功能?

时间:2020-09-26 10:19:20

标签: c++ c++20 rvalue-reference perfect-forwarding forwarding-reference

考虑如下函数:

auto&& just(auto&& arg) { return std::forward<decltype(arg)>(arg); }

这将完善转发所有引用,并在调用临时对象时返回无效引用。

更多详细信息:

struct Something {};
auto something() { return Something{}; }

auto&& ref = just(something()); // ERROR: Here ref refers to already destructed Something.

auto&& hold = something();
auto&& ref = just(hold);   // OK: Here ref refers to lifetime-extended Something.

问题是:一个人如何定义just,这样第一个调用将无法编译,而第二个调用将编译?

1 个答案:

答案 0 :(得分:0)

正如πάντα ῥεῖ在注释中指出的那样,如果您需要一个左值,则应以这种方式编写函数(单个&):

[根据您的评论,我使用了c ++ 17样式]

template <typename Arg>
auto && just(Arg & arg);

但是,我认为您的现实世界问题并不那么简单,您更喜欢在函数内部编写需求:

#include <type_traits>

template <typename Arg>
auto && just(Arg && arg) {

    static_assert(std::is_lvalue_reference_v<Arg&&>);

    return std::forward<Arg>(arg);
}

示例:一个函数执行一些工作然后以完美的转发返回函数的输出以避免复制是很实际的,但是您需要检查其返回类型。对于那些无法使用concepts的人,在函数内进行检查变得更聪明了:

#include <iostream>
#include <type_traits>

template <typename Func>
auto && just (Func && func)
{
    using return_type = decltype(func());
    
    static_assert(std::is_reference_v<return_type>, "returning temportary");

    // calculate arguments for func
    // (no args here for simplicity)

    return func(); // always return ref
}

int global;
int ReturnCopy () { return int(); }
int & ReturnGlobal () { return global; }
int && ReturnTemporary () { return std::move(global); }

int main ()
{
    just(ReturnCopy); // <--- error
    just(ReturnGlobal);
    just(ReturnTemporary);
}