Как условно создать экземпляр класса шаблона, который имеет более одного параметра шаблона? - PullRequest
6 голосов
/ 03 мая 2019

Я подписался на этот пост: Шаблон класса SFINAE создать экземпляр класса шаблона условно .

Это прекрасно работает для классов, которые имеют только один параметр шаблона, как показано в ссылке выше.

Однако у меня есть два (шаблонных) аргумента, и я хотел бы выполнить определенную проверку SFINE. Ниже приведен минимальный пример моего кода.

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

выше дал мне сообщение об ошибке: 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'

К сожалению, я не смог понять сообщение об ошибке (error C3855:).

Почему я не могу использовать тот же принцип, показанный в приведенной выше ссылке, для дополнительных параметров шаблона ?

А что является лучшим решением для этого?

1 Ответ

6 голосов
/ 03 мая 2019

Проблема в шаблонной специализации MyClass.Специализация должна быть параметризована только для двух классов T и U, тест должен быть помещен в объявление, как в примере ниже.

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

Демо: https://godbolt.org/z/xTnwo9

...