7

Say I have a variadic template class. How do I create a function such that it's arguments are of a set type, for example int, with the number of arguments being equal to the number of template types?

template <typename... Types>
class Test
{
public:
    void Func(???); // I don't know how to declare such a function
}

Test<string, bool, long> myTest; // Three types
myTest.Func(905, 36, 123315); // Three arguments, but always of type int.

In the end, the goal of the function is to return a tuple of the provided ints. For simplicity I showed the function to be void in the example code.

Piotr Skotnicki
  • 46,953
  • 7
  • 118
  • 160
Aart Stuurman
  • 3,188
  • 4
  • 26
  • 44
  • [This](http://stackoverflow.com/questions/3703658/specifying-one-type-for-all-arguments-passed-to-variadic-function-or-variadic-te) with additional `sizeof...`check? – LogicStuff Oct 13 '16 at 07:54
  • Like this? http://ideone.com/PASclP – Simon Kraemer Oct 13 '16 at 07:56
  • 1
    You don't even need `Types` here since the parameter pack size can be deduced by the call : http://ideone.com/tPe6Tj – Hatted Rooster Oct 13 '16 at 07:59
  • @Simon Kraemer I want Func to have a number of arguments equal to the number of class template types. In addition I want to force them to always be an integer. – Aart Stuurman Oct 13 '16 at 07:59
  • @Gill Bates That is getting pretty close. Next up for me: How to have a return type std::tuple<> containing a number of ints equal to the number of types? – Aart Stuurman Oct 13 '16 at 08:03

2 Answers2

18
template <typename... Types>
class Test
{
    template <typename>
    using int_t = int;

public:    
    void Func(int_t<Types>... ints)
    {
    }
};

DEMO

Piotr Skotnicki
  • 46,953
  • 7
  • 118
  • 160
  • 1
    Clever! I like this solution. – Vittorio Romeo Oct 13 '16 at 08:12
  • 1
    Note that your solution allows implicit conversions - not sure if that's what the OP wants. – Vittorio Romeo Oct 13 '16 at 08:13
  • Could you maybe elaborate on how this works? I have never seen a template and using combined. – Aart Stuurman Oct 13 '16 at 08:17
  • 3
    @AartStuurman it's an alias template, designed in a way such that whatever you specify as a type template argument, say `T`, then `int_t` will always be replaced by `int`. The unused type template parameter is there to exploit pack expansion and generate a function parameter list – Piotr Skotnicki Oct 13 '16 at 08:30
4

wandbox example - (works with C++11)


If you do not require SFINAE, you can use static_assert to make sure your conditions are met:

template <typename... Types>
class Test
{
public:
    template <typename... Ts>
    void Func(Ts...)
    {
        static_assert(sizeof...(Ts) == sizeof...(Types), "");
        static_assert(std::conjunction<std::is_same<Ts, int>...>{}, "");
    }
};

(If you need SFINAE, use std::enable_if.)

std::conjunction checks that all the conditions passed to it are true.


With the above example, the following calls are valid/invalid:

myTest.Func(905, 36, 123315); // valid
myTest.Func(905, 36, 123315.f); // invalid
myTest.Func(905, 22); // invalid

As you can see, implicit conversions are not allowed with this solution. You could use std::is_convertible instead of std::is_same if you want them to be allowed.

Vittorio Romeo
  • 90,666
  • 33
  • 258
  • 416