Felix Dombek
Felix Dombek

Reputation: 14356

Return a class template with value template arguments from function

Suppose I have a simple template class:

template <typename ElementType, ElementType Element>
class ConsecutiveMatcher
{
public:
    bool operator () (ElementType lhs, ElementType rhs)
    {
        return lhs == Element && rhs == Element;
    }
};

I would usually make instantiation simpler than ConsecutiveMatcher<wchar_t, L'\\'>() by providing a function which can infer the template argument types based on the parameter types:

template <typename ElementType>
ConsecutiveMatcher<ElementType, Element /* ?? */> 
    MakeConsMatcher(ElementType Element)
{
    return ConsecutiveMatcher<ElementType, Element>();
}

However, in this case, MakeConsMatcher(L'\\') will not work, because the function needs to return a class whose template does not only contain a type, but also a value.

How can I return a class template from a function which has not only type template arguments, but also value template arguments?

Upvotes: 0

Views: 1337

Answers (2)

Drop
Drop

Reputation: 13005

I'm just looking for a way to omit the wchar_t and use automatic type deduction during instantiation.

I can imagine such situations:

  1. Argument type only known at runtime (and you have no any idea about it): you cannot handle it with templates: you will want to redesign your code and use inheritance and virtual functions (or, probably, mix both, templates and inheritance)

  2. Argument type known at compile-time, argument value known at runtime: left Type of argument in template argument list and pass argument value to constructor, then, for user's convenience, make factory function to deduce type

    template<typename T>
    struct MyType
    {
        template <class T>
        MyType(const T& defaultValue) :
             value(defaultValue)
        {}
        T value;
    };
    
    template<typename T>
    MyType<T> MyFactory(const T& defaultValue)
    {
        return MyType<T>(defaultValue);
    }
    
    int main()
    {
        char c = 'a';
        wchar_t w = L'a';
        int i = 42;
        float f = 3.14f;
    
        auto mt_char = MyFactory(c);
        auto mt_wchar = MyFactory(w);
        auto mt_int = MyFactory(i);
        auto mt_float = MyFactory(f);
    }
    
  3. At compile-time you know a list of Types and want they behave differently (for example have different default values): make template specializations for each type from a list, then, for user's convenience, create typedefs

      template<typename T> struct MyType
      {
            MyType(const T& defaultValue) :
        value(defaultValue)
              {}
    
         T value;
     };
    
     template<>
     struct MyType <char>
     {
        MyType() :
         value('c')
        {}
    
        char value;
     };
    
    
     template<>
     struct MyType <wchar_t>
     {
        MyType() :
         value(L'w')
        {}
    
        wchar_t value;
     };
    
     typedef MyType<char> MyTypeChar;
     typedef MyType<wchar_t> MyTypeWchar;
    
     int main()
     {
       MyTypeChar mt_char_default;
       MyTypeWchar mt_wchar_default;
     }
    

In this case, user still can instantiate own specializations. Example of that approach is a std::basic_string class. Further, you can simplify your specializations, if make class members static or static const and for integral types just define in member list:

template<>
struct MyType <char>
{
    static const char value = 'c';
};

Upvotes: 1

Tiemo Jung
Tiemo Jung

Reputation: 146

You want a runtime computed value turned into an template argument? it's not possible.

Upvotes: 1

Related Questions