Default values in templates with template arguments ( C++ )

后端 未结 6 967
名媛妹妹
名媛妹妹 2020-12-05 05:03

Assume I have a template (called ExampleTemplate) that takes two arguments: a container type (e.g. list, vector) and a contained type (e.g. float, bool, etc). Since containe

6条回答
  •  暗喜
    暗喜 (楼主)
    2020-12-05 05:24

    As the question exactly described the problem I had in my code (--I'm using Visual Studio 2015), I figured out an alternative solution which I wanted to share.

    The idea is the following: instead of passing a template template parameter to the ExampleTemplate class template, one can also pass a normal typename which contains a type DummyType as dummy parameter, say std::vector.

    Then, inside the class, one replace this dummy parameter by something reasonable. For replacement of the typethe following helper classes can be used:

    // this is simply the replacement for a normal type:
    // it takes a type T, and possibly replaces it with ReplaceByType
    template
    struct replace_type
    {
        using type = std::conditional_t::value, ReplaceByType, T>;    
    };
    
    // this sets up the recursion, such that replacement also happens
    // in contained nested types
    // example: in "std::vector >", both T's are replaced
    template class C, typename ... Args, typename ReplaceWhatType, typename ReplaceByType>
    struct replace_type, ReplaceWhatType, ReplaceByType>
    {
        using type = C::type ...>;
    };
    
    // an alias for convenience
    template
    using replace_type_t = typename replace_type::type;
    

    Note the recursive step in replace_type, which takes care that types nested in other classes are replaced as well -- with this, for example, in std::vector >, both T's are replaced and not only the first one. The same goes for more than one nesting hierarchy.

    Next, you can use this in your ExampleTemplate-class,

    struct DummyType {};
    
    template 
    struct ExampleTemplate
    {
        replace_type_t items;
    };
    

    and call it via

    int main()
    {
        ExampleTemplate, float> a;
        a.items.push_back(1.0);
        //a.items.push_back("Hello");  // prints an error message which shows that DummyType is replaced correctly
    
        ExampleTemplate, float> b;
        b.items.push_back(1.0);
        //b.items.push_back("Hello");  // prints an error message which shows that DummyType is replaced correctly
    
        ExampleTemplate, float> c;
        c.items[0]=1.0;
        //c.items[0]="Hello";          // prints an error message which shows that DummyType is replaced correctly
    }
    

    DEMO

    Beside the not-that-nice syntac, this has the advantage that

    1. It works with any number of default template parameters -- for instance, consider the case with std::map in the example.

    2. There is no need to explicitly specify any default template parameters whatsoever.

    3. It can be easily extended to more dummy parameters (whereas then it probably should not be called by users ...).

    By the way: Instead of the dummy type you can also use the std::placeholder's ... just realized that it might be a bit nicer.

提交回复
热议问题