Home Different code path according to different type in a template method
Reply: 1

Different code path according to different type in a template method

Danny Chen
1#
Danny Chen Published in 2017-12-06 09:54:59Z

Let's say I have a template class like this:

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;
    }
};

Somewhere else in the project process_core is implemented for different TRequest/TResponse types. For example:

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

Obviously return response breaks for void types. What's the correct way to do this? Or my design is not the C++ way? I'm new to C++.

Vittorio Romeo
2#
Vittorio Romeo Reply to 2017-12-06 11:21:30Z

Unfortunately void is not a regular type, even though there's a proposal that aims to fix that ("regular void" by Matt Calabrese), so you need to handle it in a special way. With C++17, you can simply use if constexpr(...) to branch at compile-time:

TResponse process(const TRequest& request)
{
    TResponse response = process_core(request);
    // ...

    if constexpr(!std::is_same_v<TResponse, void>)
    {
        return response;
    }
}

With C++11/14, you can use tag dispatching:

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;
}

Alternatively, you can transform void into a regular nothing type and handle it homogeneously.

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;
}

Note that process_core must return nothing instead of void in this case, so you'll need some sort of specialization or compile-time branching anyway.

You need to login account before you can post.

About| Privacy statement| Terms of Service| Advertising| Contact us| Help| Sitemap|
Processed in 0.302343 second(s) , Gzip On .

© 2016 Powered by mzan.com design MATCHINFO