【问题标题】:Template functor wrapper that can return a void or non-void value [duplicate]可以返回 void 或非 void 值的模板函子包装器
【发布时间】:2013-08-29 17:22:03
【问题描述】:

如何从模板仿函数包装器返回任意类型(void 或 non-void)?我将包装器用于前置条件和后置条件,因此我需要将返回的值存储在局部变量中,然后再从包装器返回它。但是当返回的类型是 void 时,编译器会给出错误,因为变量不能有 void 类型。在这里可以做什么?

template <typename Functor, typename... Args>
auto Decorate(Functor f, Args&&... args)
-> decltype(f(std::forward<Args>(args)...)) {
    // preconditions
    const auto result = f(std::forward<Args>(args)...);
    // postconditions
    return result;
}

【问题讨论】:

  • 无效的前置/后置条件是什么?
  • 我可以想到两个快速的解决方案:1)将前置条件和后置条件作为单独类的 ctor 和 dtor,然后 return f(...) (您可以从模板返回 void 作为例外规则),或 2)对返回 void 的可调用对象进行重载,但这意味着重复的代码。
  • 我用它来测量一个函数的执行时间。

标签: c++ templates c++11 metaprogramming


【解决方案1】:

在合适的类的构造函数/析构函数中运行你的前置条件和后置条件并直接返回值!只要您不需要触摸后置条件中的返回值,这应该不是问题!

struct condition
{
    condition() { /* do pre-condition checks */ }
    ~condition() { /* do post-condition checks */ }
    condition(condition&) = delete;
    void operator= (condition&) = delete;
};
template <typename Functor, typename... Args>
auto Decorate(Functor f, Args&&... args)
    -> decltype(f(std::forward<Args>(args)...)) {
    condition checker;
    return f(std::forward<Args>(args)...);
}

【讨论】:

    【解决方案2】:

    使用 sfinae:

    #include <type_traits>
    
    template <typename Functor, typename... Args>
    auto Decorate(Functor f, Args&&... args)
        -> typename std::enable_if<std::is_same<decltype(f(std::forward<Args>(args)...)), void>::value, void>::type
    {
        // preconditions
        f(std::forward<Args>(args)...);
        // postconditions
        return;
    }
    
    template <typename Functor, typename... Args>
    auto Decorate(Functor f, Args&&... args)
        -> typename std::enable_if<!std::is_same<decltype(f(std::forward<Args>(args)...)), void>::value, decltype(f(std::forward<Args>(args)...))>::type
    {
        // preconditions
        auto result = f(std::forward<Args>(args)...);
        // postconditions
        return result;
    }
    

    测试:

    void f(int x) {
        std::cout << "f(" << x << ")" << std::endl;
        return;
    }
    
    int g(int x) {
        std::cout << "g(" << x << ")" << std::endl;
        return x * x;
    }
    
    int main()
    {       
        Decorate(f, 3);
        std::cout << Decorate(g, 3);
        return 0;
    }
    

    f(3)
    g(3)
    9

    【讨论】:

    • 您可以将decltype(...) 替换为typename std::result_of&lt;Functor&gt;::type
    • @0x499602D2 我猜你的意思是typename std::result_of&lt;Functor(Args...)&gt;::type
    • @G.Civardi 是的,我做到了。谢谢!
    • @0x499602D2 - 我刚刚在使用该构造时遇到了问题 :-) 感谢您的评论。
    猜你喜欢
    • 1970-01-01
    • 2019-10-08
    • 2021-06-27
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2017-05-15
    • 2015-11-14
    • 1970-01-01
    相关资源
    最近更新 更多