Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Variadic template specialization in C++11

Is it implemented already, because this does not compile: (using gcc 4.7.2)

template <typename... Ts>
struct Foo {
    int foo() {
        return 0;
    }
};

template <>
struct Foo<int x, int y> {
    int foo() {
        return x * y;
    }
};

int main()
{
    Foo<2, 3> x;
    cout << x.foo() << endl; //should print 6
}
like image 543
Cartesius00 Avatar asked Nov 22 '12 15:11

Cartesius00


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 a Variadic template 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.

Which of the following are valid reasons for using Variadic templates 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 means variadic?

variadic (not comparable) (computing, mathematics, linguistics) Taking a variable number of arguments; especially, taking arbitrarily many arguments.


1 Answers

You are making a few mistakes. The primary template expects types, not integral constants. You also try to instantiate the template with integral constants, but your partial specialization uses types.

This is closer:

#include <iostream>

template <int... Ts>
struct Foo {
    int foo() {
        return 0;
    }
};

template <>
struct Foo<3, 2> {
  const int x = 3;
  const int y = 2;

  int foo() {
    return x * y;
  }
};

int main()
{
    Foo<2, 3> x;
    std::cout << x.foo() << std::endl; //should print 6
}

But this is not really what we want, right? And it is also clumsy.

#include <iostream>

template<typename Acc, typename... Rest>
struct accum_help; // primary

template<typename Acc, typename F, typename... Rest>
struct accum_help<Acc, F, Rest...> {
  typedef typename accum_help<
    std::integral_constant<typename Acc::value_type, 
                           Acc::value * F::value>, Rest...
    >::type type;
};

template<typename Acc>
struct accum_help<Acc> {
  typedef Acc type;
};

// peek into the first argument to avoid summing empty sequences and
// get the right type
template<typename X, typename... Integrals>
struct accum {
  typedef typename accum_help<
    std::integral_constant<typename X::value_type, 1>, X, Integrals...
    >::type type;
};

int main()
{

  std::cout << accum< std::integral_constant<int, 2>, std::integral_constant<int, 3> >::type::value << std::endl; //should print 6
}

A simpler variant handling only int:

template <int...>
struct accum2_help;

template <int Acc, int X, int... Rest> 
struct accum2_help<Acc, X, Rest...> {
  static const int value = accum2_help< Acc * X, Rest...>::value;
};

template <int Acc>
struct accum2_help<Acc> {
  static const int value = Acc;
};

// again don't accept empty packs
template <int T, int... Ts>
struct accum2 {
  static const int value = accum2_help<1, T, Ts...>::value;
};
like image 116
pmr Avatar answered Sep 18 '22 14:09

pmr