Как я могу сделать конструктор по умолчанию условно явным? - PullRequest
2 голосов
/ 28 апреля 2019

Задача

Предположим, у нас есть (вымышленный) шаблон класса C<T> с условно явным конструктором по умолчанию. Конструктор по умолчанию должен быть явным тогда и только тогда, когда std::is_same_v<T, int>.

Поиск по «[c ++] условно явно» возвращает этот результат: Конструктор условно помечен явно .

Неудачное решение

Принятый ответ приводит пример:

struct S {
  template <typename T,
             typename std::enable_if<std::is_integral<T>::value, bool>::type = false >
  S(T) {}

  template <typename T,
            typename std::enable_if<!std::is_integral<T>::value, bool>::type = false>
  explicit S(T) {}
};

Небольшое изменение примера дает эту реализацию, которая использует знакомый подход std::enable_if:

template <class T>
class C {
public:
  template <std::enable_if_t<std::is_same_v<T, int>, int> = 0>
  C() {}

  template <std::enable_if_t<!std::is_same_v<T, int>, int> = 0>
  explicit C() {}
};

К сожалению, это даже не компилируется: demo

prog.cc: In instantiation of 'class C<int>':
prog.cc:15:10:   required from here
prog.cc:10:12: error: no type named 'type' in 'struct std::enable_if<false, int>'
   10 |   explicit C() {}
      |            ^
prog.cc: In instantiation of 'class C<double>':
prog.cc:18:13:   required from here
prog.cc:7:3: error: no type named 'type' in 'struct std::enable_if<false, int>'
    7 |   C() {}
      |   ^

Проблема, по-видимому, вызвана отсутствием параметра шаблона в конструкторе и отключением SFINAE.

Вопрос

  1. Почему это не компилируется?
  2. Что такое возможная реализация?

Я хотел бы избежать специализации класса, если это возможно.

1 Ответ

2 голосов
/ 28 апреля 2019
Что такое возможная реализация?

Вы пробовали с

template <class T>
class C {
public: //  VVVVVVVVVVVVVV .................................V  U here, not T
  template <typename U = T, std::enable_if_t<std::is_same_v<U, int>, int> = 0>
  C() {}

  template <typename U = T, std::enable_if_t<!std::is_same_v<U, int>, int> = 0>
  explicit C() {}
};

?

  1. Почему этоне компилируется?

Проблема в том, что SFINAE, над методами класса, работает с параметрами шаблона самих методов.

То есть в исходном рабочем коде:

  template <typename T,
             typename std::enable_if<std::is_integral<T>::value, bool>::type = false >
  S(T) {}

где T - это параметр шаблона, специфичный для конструктора (выводится из единственного аргумента).

Напротив, в вашем ошибочном коде

template <std::enable_if_t<std::is_same_v<T, int>, int> = 0>
C() {}

конструкторы оценивают параметр шаблона класса (T), а не методов.

Используя трюк typename U = T, вы преобразуете T, параметр шаблона класса, вU, параметр шаблона методов (в вашем случае конструкторы, но работает и с другими методами), поэтому std::enable_if_t с тестом, зависящим от U, может включать / отключать конструкторы.

...