根据模板方法中的不同类型的不同代码路径

时间:2017-12-06 09:55:00

标签: c++ templates template-classes

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

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 ++的新手。

1 个答案:

答案 0 :(得分:13)

不幸的是,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,因此无论如何您都需要某种特化或编译时分支。