C++11: Number of Variadic Template Function Parameters

C++11: Number of Variadic Template Function Parameters?

Just write this:

const std::size_t n = sizeof...(T); //you may use `constexpr` instead of `const`

Note that n is a constant expression (i.e known at compile-time), which means you may use it where constant expression is needed, such as:

std::array<int,   n>  a; //array of  n elements
std::array<int, 2*n> b; //array of (2*n) elements

auto middle = std::get<n/2>(tupleInstance);

Note that if you want to compute aggregated size of the packed types (as opposed to number of types in the pack), then you've to do something like this:

template<std::size_t ...>
struct add_all : std::integral_constant< std::size_t,0 > {};

template<std::size_t X, std::size_t ... Xs>
struct add_all<X,Xs...> :
std::integral_constant< std::size_t, X + add_all<Xs...>::value > {};

then do this:

constexpr auto size = add_all< sizeof(T)... >::value;

In C++17 (and later), computing the sum of size of the types is much simpler using fold expression:

constexpr auto size = (sizeof(T) + ...);

Hope that helps.

Limit the number of parameters in a variadic template parameter pack

To make the function not callable when there's too many arguments, you can constraint the function with sfinae. That way, if there's another overload that accepts more arguments, the compiler will be able to select the correct overload.

A simple std::enable_if with the condition will suffice:

template <class ...Args, std::enable_if_t<(sizeof...(Args) <= 10)>* = nullptr>
void setRequestArguments(const Args&... args)
{
const std::vector<QGenericArgument> vec = {args... };
}

For the sake of readability, you can put the constraint in the trailing return type of your function:

template <class ...Args>
auto setRequestArguments(const Args&... args) -> std::enable_if_t<(sizeof...(args) <= 10)>
{
const std::vector<QGenericArgument> vec = {args... };
}

Here's an updated version for C++20 using requires and terse template syntax:

auto setRequestArguments(const auto&... args) requires (sizeof...(args) <= 10) -> void {
const std::vector<QGenericArgument> vec = {args... };
}

C++ Getting a number of elements in variadic template

If T were a parameter pack, you could use the following syntax to declare a function that takes a sequence of parameters with types corresponding to those in the parameter pack:

inline Class<T>::Test(const T&... t) { /* ... */ }

However, it appears that T isn't a parameter pack. It's just a single type parameter. Plus, you put the ... in the wrong place. So what you really did was declare a function that takes a single parameter of type T, plus a C-style ellipsis. (Yes, the comma before the ellipsis is optional!)

So when you write sizeof...(t), the compiler complains because t is not a pack. It's just a normal parameter.

Perhaps you wanted to declare Test to be a function that takes an arbitrary number of arguments, but all of type const T&? Unfortunately, there is no easy way to do that in current C++. See Specifying one type for all arguments passed to variadic function or variadic template function w/out using array, vector, structs, etc? for solutions.

C++ variadic template sum

You need the "stop-recursion-case" (do not know the correct name now; UPDATE: it's called "base-case", thanks Quentin) with just one argument when the template function is unfolding.

#include <iostream>

template<typename T>
T adder(T first) {
return first;
}

template<typename T, typename... Args>
T adder(T first, Args... args) {
return first + adder(args...);
}

int main() {
const int c = adder(1, 8, 4);
std::cout << c << '\n';
return 0;
}

C++ variadic function: use number of parameters as template argument

Like this:

template<int N>
class Vec {};

template<typename... Args>
auto foo(Args&&...) -> Vec<sizeof...(Args)>;

int main()
{
auto v = foo(1,2,3);
Vec<1> vv = foo(5);
}

It works with the old-style function signature syntax, too (I just prefer trailing return type in this particular case).

C++ function with a viariable number of arguments of a certain type

If the compiler supports C++ 20 then you can write for example

#include <type_traits>

template <typename T, uint16_t dimension>
class Vector
{
public:
template <typename... Ts>
Vector( Ts &&... args ) requires ( sizeof...( args ) == dimension ) && std::conjunction_v<std::is_same<T, std::decay_t<Ts>>...>
{
}
};

//...

Vector<float, 5> v( 1.1f, 2.2f, 3.3f, 4.4f, 5.5f );

Or as @HolyBlackCat wrote in a comment you may also write

template <typename T, uint16_t dimension>
class Vector
{
public:
template <typename... Ts>
Vector( std::same_as<T> auto ...args ) requires( sizeof...( args ) == dimension )
{
}
};

Is there a way to define a variadic number of arguments of the same type?

I can't figure out how to implement a function with a variable number of arguments of the same type.

Template argument of the same type or ordinary function arguments of the same type?

The first case is simple (if the type is one admitted for template value types), exactly as you have written

template<S* s, int... args>
fun (int arg1, int arg2);

and you can use they using template folding, if you can use C++17,

template <S* s, int... args>
auto fun (int arg1, int arg2)
{ ((s->r1 += 7 * args), ...); }

or in a little more complicated way before (C++11/C++14)

template <S* s, int... args>
auto fun (int arg1, int arg2)
{
using unused = int[];

(void)unused { 0, s->r1 += 7 * args ... };
}

Unfortunately you can call this type of function with compile time known integers so, by example, not with variables

int a = 7;
fun<&s,1,2,a,4>(mode,speed); // compilation error

In this case you need a variadic list of ordinary function arguments of the same type; unfortunately this is a little more complicated.

You can create a typical variadic list of template parameter

template <typename ... Args>
auto fun (Args ... args)

imposing, through SFINAE, that all Args... are deduced or explicated as int (see Michael Kenzel's answer).

Unfortunately this require that every argument is exactly if type int so calling func with (by example) a long int gives a compilation error

fun(1, 2, 3l); // compilation error (3l is a long int, not an int)

Obviously you can relax the SFINAE condition imposing (by example) that all Args... types are convertible (std::is_convertible) to int but isn't exactly has developing a function receiving a variadic number of arguments of the same type.

If you can accept a superior limit to the number of arguments (64, in the following example) and that the function is method (maybe static) of a class, you can create a foo class containing a method f() that receive zero int, one f() that receive one int, one f() that receive two ints, etc, until an f() that receive 63 ints.

The following is a full compiling C++17 example

#include <utility>
#include <type_traits>

struct S
{
int r1;
int r2;
};

S s;
const int mode=3, speed=1;

template <typename T, std::size_t>
using getType = T;

template <std::size_t N, typename = std::make_index_sequence<N>>
struct bar;

template <std::size_t N, std::size_t ... Is>
struct bar<N, std::index_sequence<Is...>>
{
static constexpr auto f (getType<int, Is> ... args)
{ ((s.r1 += 7 * args), ...); }
};

template <S &, std::size_t N = 64u, typename = std::make_index_sequence<N>>
struct foo;

template <S & s, std::size_t N, std::size_t ... Is>
struct foo<s, N, std::index_sequence<Is...>> : public bar<Is>...
{ using bar<Is>::f...; };

int main ()
{
foo<s>::f(mode, speed);
}

In C++14 is a little more complicated because there isn't variadic using so you have to write the foo class in a recursive way.

In C++11 you have also to develop a substitute for std::make_index_sequence/std::index_sequence.

C++11: Calculating variadic function parameter types

There's nothing like writing down the question to make you realize the answer.

Here's one way:

template<typename T, typename Args = typename args_of_var<decltype(T::f)>::type>
struct up_front_var;

template<typename T, typename... Args>
struct up_front_var<T, type_list<Args...>>
{
static void forward(Args... args)
{
T::f(args...);
}
};

I don't think there's a way to make a top-level function out of this (you run into the original problem again), but that's possibly not too bad.

Would still be happy to see other solutions.

C++11 variable number of arguments, same specific type

A possible solution is to make the parameter type a container that can be initialized by a brace initializer list, such as std::initializer_list<int> or std::vector<int>. For example:

#include <iostream>
#include <initializer_list>

void func(std::initializer_list<int> a_args)
{
for (auto i: a_args) std::cout << i << '\n';
}

int main()
{
func({4, 7});
func({4, 7, 12, 14});
}


Related Topics



Leave a reply



Submit