Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Limit the number of parameters in a variadic template parameter pack

I have a template function that takes a variable number of arguments. Since you can't force the arguments to be of a certain type I would like at least to force the number of arguments not to be higher that a compile-time determined number(e.g. 10).

Is it possible to make to compiler give an error if a template function with a parameter pack has the number of arguments higher than a compile-time determined value?

template <class ...Args>
void setRequestArguments(const Args&... args)
{
    const std::vector<QGenericArgument> vec = { args... };
    qDebug() << sizeof...(args);
    // Do stuff...
    // for (unsigned i = 0; i < vec.size(); ++i) {
    //     qDebug() << vec[i].name();
    // }
}

What I want to use it for is for a generic container for all arguments in an QMetaObject::invokeMethod wrapper function.

like image 905
Jacob Krieg Avatar asked Sep 21 '16 15:09

Jacob Krieg


People also ask

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. However, variadic templates help to overcome this issue.

What is a parameter pack in C++?

Parameter packs (C++11) A parameter pack can be a type of parameter for templates. Unlike previous parameters, which can only bind to a single argument, a parameter pack can pack multiple parameters into a single parameter by placing an ellipsis to the left of the parameter name.

What are Variadic functions in C?

Variadic functions are functions that can take a variable number of arguments. In C programming, a variadic function adds flexibility to the program. It takes one fixed argument and then any number of arguments can be passed.

How do you access variadic arguments?

To access variadic arguments, we must include the <stdarg. h> header.


2 Answers

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... };
}
like image 194
Guillaume Racicot Avatar answered Oct 18 '22 21:10

Guillaume Racicot


Is it possible to make to compiler give an error if a template function with a parameter pack has the number of arguments higher than a compile-time determined value?

Yes, use static_assert:

template <class ...Args>
void setRequestArguments(const Args&... args)
{
    static_assert(sizeof...(args) <= 10, "You can't have more than 10 arguments!");
    //Stuff...
}
like image 25
Rakete1111 Avatar answered Oct 18 '22 21:10

Rakete1111