Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How do I enable_if a class with variadic template arguments?

Tags:

c++

templates

Suppose I have a class with the following signature:

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

But how this class behaves should depend on some other parameter, let's say it's the value of 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; }

However, this program gives the following error:

prog.cpp:6:11: error: parameter pack ‘Args’ must be at the end of the template parameter list class A;

I have struggled to find a good source of information on the use of enable_if to select classes with variadic templates. The only question I could find is this one:

How to use std::enable_if with variadic template

But despite the name, this question and its answers aren't much help. If someone could provide or link a guide on how this should be approached and why that would be appreciated.

like image 430
quant Avatar asked Oct 17 '14 08:10

quant


People also ask

What is Variadic template in C++?

Variadic templates are class or function templates, that can take any variable(zero or more) number of arguments. In C++, templates can have a fixed number of parameters only that have to be specified at the time of declaration. However, variadic templates help to overcome this issue.

What is enable if?

The enable_if family of templates is a set of tools to allow a function template or a class template specialization to include or exclude itself from a set of matching functions or specializations based on properties of its template arguments.


Video Answer


2 Answers

First of all, what you're trying is writing multiple definitions of a class template. That's not allowed because it violates One definition rule. If you want to do conditional enabling with classes, you need specializations. Also, the compiler error message already told you, you can't have a variadic parameter pack in the middle of a parameter list.

One way to do it would be:

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's way is also perfectly fine if the condition is really a bool, but it might not be useful if you wish to add more specializations that each depend on several conditons.

like image 61
jrok Avatar answered Sep 19 '22 23:09

jrok


It looks as though for your purposes you don't need to enable/disable the class, you just need a partial specialization:

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...>;
like image 35
Jonathan Wakely Avatar answered Sep 17 '22 23:09

Jonathan Wakely