16

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.

Jacob Krieg
  • 2,834
  • 15
  • 68
  • 140
  • 1
    it is possible to restrict the arguments to a certain type. Do you want an answer on this? Do you require the arguments to be exactly `T` or something convertible to `T`? – bolov Sep 22 '16 at 14:46
  • @bolov Yes, please, that would be extremely useful! I will +1 – Jacob Krieg Sep 22 '16 at 20:01
  • 1
    I created a new post with exactly this: http://stackoverflow.com/questions/39659127/restrict-variadic-template-arguments/39659128#39659128 – bolov Sep 23 '16 at 11:00
  • @bolov great post, thanks! – Jacob Krieg Sep 24 '16 at 16:42

2 Answers2

29

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... };
}
Guillaume Racicot
  • 39,621
  • 9
  • 77
  • 141
18

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...
}
Rakete1111
  • 47,013
  • 16
  • 123
  • 162