c++templatestemplate-meta-programmingpolicypolicy-based-design

C++ Template Meta Programming: Inheritance from template template parameter


#include <type_traits>

template <typename T1, typename T2, typename is_allocated>
struct mutable_storage {};

template <
    template<typename, typename, typename> class storage_t,
    typename T2           = void,
    typename is_allocated = std::false_type
>
class Buffer : storage_t<Buffer<storage_t,void,void>, T2, is_allocated>
{};



int main() {
    typedef Buffer<mutable_storage> example_buffer;
}

This code compiles (at least using the GNU GCC Compiler following C++14). However, I dislike the used syntax

class Buffer : storage_t<Buffer<storage_t,void,void>, T2, is_allocated>

due to the fact it shouldn't require the Buffer to be specialized: I would like Buffer to be recognized as a template template parameter, like:

class Buffer : storage_t<Buffer, T2, is_allocated>

Then I would like the mutable_storage struct to recognize a template specialization like

template <typename T2, typename is_allocated>
struct mutable_storage<Buffer, T2, is_allocated> { ... };

(Would of course not be allowed, as "Buffer" is not a type, so that should be changed too). But the way it uses right now, being able to specialize with type Buffer feels a bit nasty. Using a typedef, for example

 typedef Buffer<storage_t, void, void> Buffer_Policy

also feels a bit nasty. I'm looking for a cleaner way. I've tried to make a template template template parameter, but that leads to an infinite flow of extra templates within the template parameter (I don't know exactly how template<...> works, so maybe that?), as the Buffer inherits from something that requires another Buffer in order to declare storage_t. I've also tried using a implicit class, namely inner_storage_t. Neither did this lead to a success. Does anyone have suggestions in order to make the program cleaner? By the way, if you see any other mistakes or inefficiencies, feel free to mention it. Thanks for reading and possibly your help.


Solution

  • Since T1 is only meant to be used for template specialization selection, you don't really have to use Buffer itself. You can use a tag type instead.

    Squirreling it away in a namespace also allows you to avoid polluting the rest of the enclosing namespace with the tags.

    #include <type_traits>
    
    template <typename T1, typename T2, typename is_allocated>
    struct mutable_storage {};
    
    namespace storage_tags {
      struct Buffer_T {};
    }
    
    template <
        template<typename, typename, typename> class storage_t,
        typename T2           = void,
        typename is_allocated = std::false_type
    >
    class Buffer : public storage_t<storage_tags::Buffer_T, T2, is_allocated> { 
    
    };