从函数正确传播“decltype(auto)”变量

2024-05-08

(这是来自"“decltype(auto)”变量有任何实际用例吗? https://stackoverflow.com/questions/57438217/are-there-any-realistic-use-cases-for-decltypeauto-variables/57440814")

考虑以下场景 - 我想传递一个函数f到另一个函数invoke_log_return这将:

  1. Invoke f;

  2. 打印一些东西到stdout;

  3. 返回结果f,避免不必要的复制/移动并允许复制省略。

请注意,如果f抛出,不应该打印任何内容stdout。这是我到目前为止所拥有的:

template <typename F>
decltype(auto) invoke_log_return(F&& f)
{
    decltype(auto) result{std::forward<F>(f)()};
    std::printf("    ...logging here...\n");

    if constexpr(std::is_reference_v<decltype(result)>)
    {
        return decltype(result)(result);
    }
    else
    {
        return result;
    }
}

让我们考虑一下各种可能性:

  • When f返回一个prvalue:

    • result将是一个对象;

    • invoke_log_return(f)将是一个prvalue(符合复制省略的条件)。

  • When f返回一个lvalue or xvalue:

    • result将成为参考;

    • invoke_log_return(f)将是一个lvalue or xvalue.

您可以看到一个测试应用程序在 godbolt.org 上 https://gcc.godbolt.org/z/iwhVHN。如你看到的,g++执行 NRVO 的prvalue情况下,同时clang++没有。

问题:

  • 这是“完美”返回的最短方法吗?decltype(auto)函数中的变量?有没有更简单的方法来实现我想要的?

  • Can the if constexpr { ... } else { ... }模式被提取到一个单独的函数?提取它的唯一方法似乎是宏。

  • 有什么充分的理由吗clang++不执行 NRVOprvalue上面的情况?是否应该将其报告为潜在的增强功能,或者是g++NRVO 优化在这里不合法?


这是使用的替代方案on_scope_success助手(按照 Barry Revzin 的建议):

template <typename F>
struct on_scope_success : F
{
    int _uncaught{std::uncaught_exceptions()};

    on_scope_success(F&& f) : F{std::forward<F>(f)} { }

    ~on_scope_success()
    {
        if(_uncaught == std::uncaught_exceptions()) {
            (*this)();
        }
    }
};

template <typename F>
decltype(auto) invoke_log_return_scope(F&& f)
{
    on_scope_success _{[]{ std::printf("    ...logging here...\n"); }};
    return std::forward<F>(f)();
}

While invoke_log_return_scope更短,这需要函数行为的不同思维模型和新抽象的实现。令人惊讶的是,两者g++ and clang++使用此解决方案执行 RVO/复制消除。

godbolt.org 上的实例 https://gcc.godbolt.org/z/7Zl9b_

正如所提到的,这种方法的一个主要缺点本·沃伊特 https://stackoverflow.com/users/103167/ben-voigt,是返回值f不能是日志消息的一部分。


这是最简单、最清晰的写法:

template <typename F>
auto invoke_log_return(F&& f)
{ 
    auto result = f();
    std::printf("    ...logging here... %s\n", result.foo());    
    return result;
}

海湾合作委员会获得正确(没有不必要的复制或移动)预期结果:

    s()

in main

prvalue
    s()
    ...logging here... Foo!

lvalue
    s(const s&)
    ...logging here... Foo!

xvalue
    s(s&&)
    ...logging here... Foo!

因此,如果代码清晰,具有相同的功能,但没有像竞争对手那样优化运行,那么这是编译器优化失败,clang 应该解决这个问题。这种问题在工具中解决而不是在应用程序层实现中更有意义。

https://gcc.godbolt.org/z/50u-hT https://gcc.godbolt.org/z/50u-hT

本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

从函数正确传播“decltype(auto)”变量 的相关文章

随机推荐