Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

A variadic template method to accept a given number of doubles?

template <unsigned int N> class myclass
{
public:
    template <typename... Args> void mymethod(Args... args)
    {
       // Do interesting stuff
    } 
};

I want mymethod to be called only with exactly N doubles. Is that possible? That is, say that I have:

myclass <3> x;
x.mymethod(3., 4., 5.); // This works
x.mymethod('q', 1., 7.); // This doesn't work
x.mymethod(1., 2.); // This doesn't work

How can I get this done?

like image 342
Matteo Monti Avatar asked May 11 '15 23:05

Matteo Monti


People also ask

What is the use of Variadic templates?

With the variadic templates feature, you can define class or function templates that have any number (including zero) of parameters. To achieve this goal, this feature introduces a kind of parameter called parameter pack to represent a list of zero or more parameters for templates.

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.

Why use variadic templates in C++?

A variadic template is a class or function template that supports an arbitrary number of arguments. This mechanism is especially useful to C++ library developers: You can apply it to both class templates and function templates, and thereby provide a wide range of type-safe and non-trivial functionality and flexibility.

How to unpack parameter pack C++?

To unpack a parameter pack, use a templated function taking one (or more) parameters explicitly, and the 'rest' of the parameters as a template parameter pack.


2 Answers

For the number of arguments constraint you can easily check if sizeof...(Args) == N but for checking if all the arguments are doubles you need to build a recursive type trait that checks std::is_same for each of the arguments.

template<typename...>
struct are_same : std::true_type 
{};

template<typename T>
struct are_same<T> : std::true_type
{};

template<typename T, typename U, typename... Types>
struct are_same<T, U, Types...> :
    std::integral_constant<bool, (std::is_same<T, U>::value && are_same<T, Types...>::value)>
{};

Notice are_same is first declared and then specialized.

Then just implement the constraint in your method return type using std::enable_if by taking advantage of SFINAE.

template <unsigned int N> class myclass
{
public:
    template <typename... Args>
    typename std::enable_if<(are_same<double, Args...>::value && sizeof...(Args) == N), void>::type
    /* void */ mymethod(Args... args)
    {
        // Do interesting stuff
    } 
};
like image 61
Denilson Amorim Avatar answered Oct 07 '22 23:10

Denilson Amorim


Can try something like following :

#include <type_traits>

template<class T, class...>
struct all_same : std::true_type
{};

template<class T, class U, class... TT>
struct all_same<T, U, TT...>
    : std::integral_constant<bool, std::is_same<T,U>{} && all_same<T, TT...>{}>
{};


template <unsigned int N> class myclass
{
    public:
    template <typename... Args>
     typename std::enable_if<sizeof...(Args) == N, void >::type mymethod(Args... args)
    {
        static_assert(all_same<double, Args...>{}, 
                      "Not all args as Double");
    }
};

<Demo>

like image 32
P0W Avatar answered Oct 07 '22 22:10

P0W