Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How to conditionally instantiate a template class which has more than one template parameter?

I have followed this post: Class template SFINAE to instantiate the template class conditionally.

That works perfectly for the classes which have only one template parameters, as shown in the link above.

However, I have two (template)arguments, and I would like to do certain SFINE check. Following is a minimal example of my code.

#include <type_traits>
#include <string>

template<class T, class U, class R> using arithmetic_types =  std::enable_if_t<
    std::is_arithmetic_v<T> &&
    std::is_arithmetic_v<U>,
    R
>;

template<class T, class U, class Enable = void> class MyClass;
template<class T, class U, arithmetic_types<T, U, void>> 
class MyClass {
public:
    MyClass() = default;
};

int main()
{
    MyClass<int, int> o;          // should work
    MyClass<int, double> o1;      // should work
    MyClass<int, std::string> o2; // should be a complier error
    return 0;
}

Above gave me the error message: https://godbolt.org/z/BEWJMp

error C3855: 'MyClass': template parameter 'Enable' is incompatible with the declaration
error C2079: 'o' uses undefined class 'MyClass'
error C2079: 'o1' uses undefined class 'MyClass'
error C2079: 'o2' uses undefined class 'MyClass'

Unfortunately, I could not understand the error message(error C3855:).

Why I can't do the same principle shown in the above link to more template parameters?

And what is the best solution for this?

like image 887
User Using Avatar asked May 03 '19 07:05

User Using


People also ask

How do you instantiate an object in a template class?

To instantiate a template class explicitly, follow the template keyword by a declaration (not definition) for the class, with the class identifier followed by the template arguments. template class Array<char>; template class String<19>; When you explicitly instantiate a class, all of its members are also instantiated.

Can a class template derive from its template parameter?

Inheriting from a template class It is possible to inherit from a template class. All the usual rules for inheritance and polymorphism apply. If we want the new, derived class to be generic it should also be a template class; and pass its template parameter along to the base class.

Can a template be a template parameter?

A template can take a parameter that is itself the name of a template. These parameters have the pleasingly repetitious name of template template parameters. template <typename T, template <typename> class Cont> class Stack; This new template parameter list for Stack looks unnerving, but it's not as bad as it appears.

How will you restrict the template for a specific datatype?

There are ways to restrict the types you can use inside a template you write by using specific typedefs inside your template. This will ensure that the compilation of the template specialisation for a type that does not include that particular typedef will fail, so you can selectively support/not support certain types.


1 Answers

The problem is in the template specialization of MyClass. The specialization should be parameterized only on the two classes T and U, the test should be put in the declaration, as in the example below.

#include <string>
#include <type_traits>

template <class T, class U, class R>
using arithmetic_types = std::enable_if_t<
    std::is_arithmetic_v<T> && std::is_arithmetic_v<U>, R>;

template <class T, class U, class Enable = void>
class MyClass;

template <class T, class U> //<- Remove the test from here
class MyClass<T, U, arithmetic_types<T, U, void>> //<- Put the test here.
{
public:
  MyClass() = default;
};

int main()
{
  MyClass<int, int> o;          // should work
  MyClass<int, double> o1;      // should work
  MyClass<int, std::string> o2; // should be a complier error
  return 0;
}

Demo: https://godbolt.org/z/xTnwo9

like image 190
Johan Avatar answered Oct 13 '22 03:10

Johan