Определение конструктора класса шаблона с enable_if вне прототипа класса
Ранее был вопрос, связанный с моей проблемой, которая касалась класса шаблона, который использовал std::enable_if
на метод, который объявлен в прототипе класса, но фактическая реализация выполняется снаружи.
Источник: реализация функции с enable_if вне определения класса
Я хочу сделать что-то подобное, но с конструктором класса, который я хочу определить вне шаблона класса с std::enable_if
metafunction.
template <typename T>
using EnableIfArithmetic = typename std::enable_if<std::is_arithmetic<T>::value, void>::type;
template <typename NumericType>
class SomeClass {
public:
// constructor definition
template <typename = EnableIfArithmetic<NumericType>>
SomeClass() {
// do some stuff
}
};
Желаемая форма:
template <typename NumericType>
class SomeClass {
public:
// constructor declaration
template <typename = EnableIfArithmetic<NumericType>>
SomeClass();
};
// constructor definition
template <typename NumericType>
template <typename = EnableIfArithmetic<NumericType>>
SomeClass<NumericType>::SomeClass() {
// constructor implementation
}
Но я не могу сделать это правильно, без ошибки компиляции. Что я делаю неправильно?
1 ответ
Значения по умолчанию для аргументов шаблона не должны повторяться в определениях. Например:
template<typename N>
struct S {
template<typename T, typename = std::enable_if_t<std::is_arithmetic_v<T>>>
S(T);
};
template<typename N>
template<typename T, typename>
S<N>::S(T) { }
То, как вы используете SFINAE, неверно: EnableIfArithmetic
должен зависеть от некоторого выведенного типа (в том же шаблоне). Пожалуйста, обратитесь к этому вопросу. Например:
template<typename T = N, typename = EnableIfArithmetic<T>>
S() { }
В противном случае произойдет серьезный сбой:
ошибка: нет типа с именем 'type' в 'struct std:: enable_if'
Если вы хотите отключить конструктор по умолчанию для некоторых типов N
Вы также можете использовать static_assert
внутри конструктора. Тем не менее, это не будет SFINAE дружелюбным.
template<typename N>
struct S1 {
public:
template<typename T = N, typename = std::enable_if_t<std::is_arithmetic_v<T>>>
S1() { }
};
template<typename N>
struct S2 {
public:
S2() { static_assert(std::is_arithmetic_v<N>); }
};
static_assert(std::is_default_constructible_v<S1<int>>);
static_assert(!std::is_default_constructible_v<S1<void>>);
static_assert(std::is_default_constructible_v<S2<int>>);
static_assert(std::is_default_constructible_v<S2<void>>);