Как включить enable_if в класс с аргументами вариационного шаблона?

Предположим, что у меня есть класс со следующей сигнатурой:

template <typename T, typename... Args>
class A;

Но как ведет себя этот класс, он должен зависеть от некоторого другого параметра, скажем, это значение T::value:

template <typename T, typename... Args, typename Enable>
class A;

template <typename T, typename... Args, typename = typename std::enable_if<T::value>::type>
class A
{
  // do something
};

template <typename T, typename... Args, typename = typename std::enable_if<!T::value>::type>
class A
{
  // do something else
};

int main() { return 0; }

Однако эта программа дает следующую ошибку:

prog.cpp: 6: 11: ошибка: пакет параметров 'Арги должны быть в конце список параметров шаблона      класс A;

Я изо всех сил пытался найти хороший источник информации об использовании enable_if для выбора классов с вариационными шаблонами. Единственный вопрос, который я смог найти, это:

Как использовать std:: enable_if с вариационным шаблоном

Но, несмотря на название, этот вопрос и его ответы не очень помогают. Если кто-то может предоставить или связать руководство о том, как к этому нужно подходить, и почему это будет оценено.

Ответ 1

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

Один из способов сделать это:

namespace detail {

template<typename T, typename Enable, typename... Args>
class A_impl;

template<typename T, typename... Args>
class A_impl<T, typename std::enable_if<T::value>::type, Args...> {
    // code here
};

template<typename T, typename... Args>
class A_impl<T, typename std::enable_if<!T::value>::type, Args...> {
    // code here
};
}

template<typename T, typename...Args>
class A : public detail::A_impl<T, void, Args...> {};

Jonathan way также отлично подходит, если условие действительно является bool, но это может быть не полезно, если вы хотите добавить больше специализаций, каждый из которых зависит от несколько условий.

Ответ 2

Похоже, что для ваших целей вам не нужно включать/отключать класс, вам просто нужна частичная специализация:

template <typename T, bool B = T::value, typename... Args>
  class A;

template <typename T, typename... Args>
  class A<T, true, Args...>;

template <typename T, typename... Args>
  class A<T, false, Args...>;