Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Member function template with the number of parameters depending on an integral template parameter

I have the following class template:

template<class T, unsigned N>
class MyClass;

where T is some type, N - number of components. It is possible to initialize the class using MyClass{a1, a2, a3} where the number of arguments is equal to N.

I want to add a member function template (let's name it foo) of MyClass that would meet the following requirements:

  1. It is templated by another type T2 (i.e. template<class T2> void foo(..))
  2. It accepts enough data to construct MyClass<T,N>, but not less and not more. Violating this results in a compile-time error.
  3. It deduces T2 from the types of the parameters. I.e. I want that it would be possible to call foo({a1, a2, a3}) or foo(a1, a2, a3) or similar, without typing <double> or MyClass<double,N> every time.

Is there a way to implement the function so that the above requirements are satisfied?

I've already thought about and/or tried the following solutions:

1) The obvious one:

...
template<class T2>
void foo(MyClass<T2, N> arg);  
...
a.foo({1,2,3}); //compile-time error

Can't work in principle, because braced initializer lists are a non-deduced context, thus they can't deduce any types. That's quite unfortunate, I'd be very happy if this worked.

2) initializer_list

Can't work in principle, because it can't check the number of arguments at compile-time.

3) Variadic template magic

Something like the function below would be neat:

template<class...T2, class std::enable_if<sizeof...(T2) == N, int>::type = 0>
void foo(T2... args);
..
foo(1,2,3);

However, I couldn't get it to work - T2 still couldn't be deduced. Maybe someone knows why? I used GCC4.7 20120121 snapshot.

4) The ugly one

Essentially this is the same as the above one, just expanded into several overloads for different N. I would better reimplement MyClass as a set of specializations for different Ns than to use this one.

template<class T2, class std::enable_if<N == 1, int>::type = 0>
void fun(T2 a1); //if N == 1
template<class T2, ..>
void fun(T2 a1, T2 a2); //if N == 2
template<class T2, ..>
void fun(T2 a1, T2 a2, T2 a3); //if N == 3
...
like image 407
p12 Avatar asked Feb 01 '12 17:02

p12


People also ask

Which template can have multiple parameters?

Function Templates with Multiple Parameters You can also use multiple parameters in your function template.

What is member function template?

Member function templates are function templates that are members of a class or class template.

What is a template template parameter in C++?

In C++ this can be achieved using template parameters. A template parameter is a special kind of parameter that can be used to pass a type as argument: just like regular function parameters can be used to pass values to a function, template parameters allow to pass also types to a function.

Can we pass Nontype parameters to templates?

Template classes and functions can make use of another kind of template parameter known as a non-type parameter. A template non-type parameter is a template parameter where the type of the parameter is predefined and is substituted for a constexpr value passed in as an argument.


2 Answers

Your third variant's second non-type param should have prefix typename not class :

template<class...T2, typename std::enable_if<sizeof...(T2) == N, int>::type = 0>
void foo(T2... args);
..
foo(1,2,3);

Check it

Gcc 4.7.0 snapshots has some bugs with templates I guess, if you try it with gcc 4.6.2/1 it shall work.

like image 102
Mr.Anubis Avatar answered Nov 15 '22 22:11

Mr.Anubis


Why not use a static_assert?

template <typename T, size_t N>
class MyClass
{
public:
    template <typename... Args>
    void foo(Args&&... args)
    {
        static_assert(sizeof...(Args) == N, "Wrong number of arguments.");
        // Rest of the implementation.
    }
};
like image 41
kennytm Avatar answered Nov 15 '22 22:11

kennytm