首页
学习
活动
专区
圈层
工具
发布
首页
学习
活动
专区
圈层
工具
MCP广场
社区首页 >问答首页 >在C++泛型编程中处理无效赋值

在C++泛型编程中处理无效赋值
EN

Stack Overflow用户
提问于 2017-12-28 01:51:18
回答 6查看 2.5K关注 0票数 31

我有包装任意lambda并返回lambda结果的C++代码。

代码语言:javascript
运行
复制
template <typename F>
auto wrapAndRun(F fn) -> decltype(F()) {
    // foo();
    auto result = fn();
    // bar();
    return result;
}

除非F返回void (error: variable has incomplete type 'void'),否则这会起作用。我想过使用ScopeGuard来运行bar,但我不希望barfn抛出异常时运行。有什么想法吗?

另外,我后来发现有个叫a proposal to fix this inconsistency的人。

EN

回答 6

Stack Overflow用户

回答已采纳

发布于 2017-12-28 04:53:16

另一个技巧可能是利用逗号运算符,例如:

代码语言:javascript
运行
复制
struct or_void {};

template<typename T>
T&& operator,( T&& x, or_void ){ return std::forward<T>(x); }

template <typename F>
auto wrapAndRun(F fn) -> decltype(fn()) {
    // foo();
    auto result = ( fn(), or_void() );
    // bar();
    return decltype(fn())(result);
}
票数 5
EN

Stack Overflow用户

发布于 2017-12-28 02:12:19

您可以编写一个简单的包装类来处理其中的这一部分:

代码语言:javascript
运行
复制
template <class T>
struct CallAndStore {
    template <class F>
    CallAndStore(F f) : t(f()) {}
    T t;
    T get() { return std::forward<T>(t); }
};

和专门化:

代码语言:javascript
运行
复制
template <>
struct CallAndStore<void> {
    template <class F>
    CallAndStore(F f) { f(); }
    void get() {}
};

你可以通过一个小的工厂函数来提高可用性:

代码语言:javascript
运行
复制
template <typename F>
auto makeCallAndStore(F&& f) -> CallAndStore<decltype(std::declval<F>()())> {
    return {std::forward<F>(f)};
}

那就用它吧。

代码语言:javascript
运行
复制
template <typename F>
auto wrapAndRun(F fn) {
    // foo();
    auto&& result = makeCallAndStore(std::move(fn));
    // bar();
    return result.get();
}

编辑:使用get中的std::forward强制转换,这似乎也可以正确地处理从函数返回引用。

票数 22
EN

Stack Overflow用户

发布于 2017-12-28 02:43:33

在这里,新的C++17 if constexpr添加可能会有所帮助。您可以选择是否在编译时返回fn()的结果:

代码语言:javascript
运行
复制
#include <type_traits>

template <typename F>
auto wrapAndRun(F fn) -> decltype(fn())
{
    if constexpr (std::is_same_v<decltype(fn()), void>)
    {
        foo();
        fn();
        bar();
    }
    else
    {
        foo();
        auto result = fn();
        bar();
        return result;
    }
}

正如您所说的,C++2a也是一个选项,您还可以利用概念,对函数施加约束:

代码语言:javascript
运行
复制
template <typename F>
  requires requires (F fn) { { fn() } -> void }
void wrapAndRun(F fn)
{
    foo();
    fn();
    bar();
}

template <typename F>
decltype(auto) wrapAndRun(F fn)
{
    foo();
    auto result = fn();
    bar();
    return result;
}
票数 14
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/47996550

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档