【问题标题】:Different code path according to different type in a template method根据模板方法中不同类型的不同代码路径
【发布时间】:2017-12-06 09:54:59
【问题描述】:

假设我有一个这样的模板类:

template<typename TRequest, typename TResponse = void>
class handler
{
private:
    TResponse process_core(const TRequest& request);
public:
    TResponse process(const TRequest& request)
    {
        //log the request        
        TResponse response = process_core(request);  //return process_core(request) works;
        //log the response, for void it's fine to log nothing
        return response;
    }
};

项目process_core 的其他地方针对不同的 TRequest/TResponse 类型实现。例如:

template<> void handler<Foo>::process_core(const Foo& foo) { }
template<> Baz handler<Bar, Baz>::process_core(const Bar& bar) { }

显然return response 会中断void 类型。这样做的正确方法是什么?还是我的设计不是 C++ 方式?我是 C++ 新手。

【问题讨论】:

    标签: c++ templates template-classes


    【解决方案1】:

    不幸的是,void 不是常规类型,尽管有一个旨在解决该问题的提案("regular void" by Matt Calabrese),因此您需要以特殊方式处理它。使用 C++17,您可以简单地使用 if constexpr(...) 在编译时进行分支:

    TResponse process(const TRequest& request)
    {
        TResponse response = process_core(request);
        // ...
    
        if constexpr(!std::is_same_v<TResponse, void>)
        {
            return response;
        }
    }
    

    使用 C++11/14,您可以使用标签调度:

    TResponse process(const TRequest& request)
    {
        return processImpl(request, std::is_same<TResponse, void>{});
    }
    
    void process(const TRequest& request, std::true_type /* void */)
    {
        TResponse response = process_core(request);
        // ...
    }
    
    TResponse process(const TRequest& request, std::false_type /* not void */)
    {
        TResponse response = process_core(request);
        // ...
        return response;
    }
    

    或者,您可以将void 转换为常规nothing 类型并同质处理。

    struct nothing { };
    
    template <typename T> 
    struct void_to_nothing { using type = T; };
    
    template <> 
    struct void_to_nothing<void> { using type = nothing; };
    
    template <typename T>
    using void_to_nothing_t = typename void_to_nothing<T>::type;
    
    auto process(const TRequest& request)
    {
        void_to_nothing_t<TResponse> response = process_core(request);
        // ...
        return response;
    }
    

    请注意,在这种情况下,process_core 必须返回 nothing 而不是 void,因此无论如何您都需要某种专门化或编译时分支。

    【讨论】:

    • 是错字吗?我以为应该是std::false_type /* not void */
    • 在修复 std::false_type 错字后,标签调度工作​​完美。我不想使用虚拟返回类型更改 process_core 实现,对我来说,标签调度是 C++14 中的最佳选择。谢谢。
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2020-05-16
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多