Как разделить объявление и реализацию шаблонного класса с параметром шаблона по умолчанию?

Мне нравится разделять объявление и реализацию моих классов. Я знаю, что реализация шаблонов классов и функций также должна идти в файл заголовка, это не проблема.

У меня проблемы с реализацией этого класса:

template <size_t S, std::enable_if_t<(S > 0), int> = 0>
class Foo {
public:
    Foo();
}

Пока я пробовал:

template<size_t S>
Foo<S>::Foo() {}

который потерпел неудачу с

ошибка C3860: в списке аргументов шаблона после имени шаблона класса должны быть указаны параметры в том порядке, в котором они указаны в списке параметров шаблона.

ошибка C2976: 'Foo ‹S, ‹__formal››': слишком мало аргументов шаблона

а также

template<size_t S, int i>
Foo<S, i>::Foo() {}

который потерпел неудачу с

ошибка C3860: в списке аргументов шаблона после имени шаблона класса должны быть указаны параметры в том порядке, в котором они указаны в списке параметров шаблона.

ошибка C3855: 'Foo ‹S, ‹un named-symbol››': параметр шаблона '__formal' несовместим с объявлением

Я также попытался изменить объявление шаблона на

template <size_t S, typename = std::enable_if_t<(S > 0)>>

что также не удалось с первым сообщением об ошибке.

Как правильно это сделать?


person IchBinKeinBaum    schedule 16.11.2017    source источник


Ответы (3)


Вы не можете частично специализировать функции шаблона (это то, что вы делаете в первом фрагменте). Если вы спрашиваете, как определить его вне класса, попробуйте следующее:

template <size_t S, std::enable_if_t<(S > 0), int> j>
Foo<S, j>::Foo(){}

Вы не можете просто заменить std::enable_if_t<(S > 0), int> на int, поскольку определения не эквивалентны (enable_if SFINAE заменяет S == 0 регистр).

Live snippet

person vsoftco    schedule 16.11.2017

Будь проще:

template <size_t S>
class Foo {
public:
    Foo();
};

template <size_t S>
Foo<S>::Foo() { }

template <>
class Foo<0>;

В этом конкретном случае я не уверен, что добавление SFINAE даст вам какие-либо дополнительные преимущества. Возможно, что даже явная специализация не нужна, и будет достаточно простого static_assert(S > 0, "!").

person Barry    schedule 16.11.2017
comment
На самом деле условие немного сложнее. Я просто сделал это для примера. Перечислять все недопустимые значения было бы непрактично. Хороший момент по поводу static_assert. Думаю, я просто был слишком взволнован тем, что попробовал enable_if. - person IchBinKeinBaum; 16.11.2017

Как правильно это сделать?

Я полагаю, второй, который вы пробовали, с typename.

Данный

template <size_t S, typename = std::enable_if_t<(S > 0)>>
class Foo {
public:
    Foo();
};

конструктор можно определить как

template <std::size_t S, typename T>
Foo<S, T>::Foo() {}

Полный пример компиляции

#include <iostream>
#include <type_traits>

template <size_t S, typename = std::enable_if_t<(S > 0)>>
class Foo {
public:
    Foo();
};

template <std::size_t S, typename T>
Foo<S, T>::Foo() {}

int main ()
 {
   Foo<12U>  f12;   // compile
   // Foo<0U>   f0; // compilation error
 }
person max66    schedule 16.11.2017