Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

variadic list vs single template parameter: what does the standard say?

Consider the following code:

#include <iostream>
#include <type_traits>

// Variadic version
template<class... Variadic>
void f(const Variadic&... variadic)
{
    std::cout<<"variadic"<<std::endl;
}

// Single version
template<class Single, class = typename std::enable_if<std::is_fundamental<Single>::value>::type>
void f(const Single& single)
{
    std::cout<<"single"<<std::endl;
}

// Main
int main()
{
    f();              // variadic
    f(42);            // single : why?
    f(std::string()); // variadic 
    f(42, 42);        // variadic
    return 0;
}

I do not understand why the line marked "single" compiles well (under g++ 4.6.3) and does not produce an overload resolution problem. Does the c++11 standard say that a template function with a fixed number of parameters is prefered over a variadic function that could have the same signature ?

like image 896
Vincent Avatar asked Jan 06 '13 07:01

Vincent


People also ask

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 is Variadic template in 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.

What is args && args?

Args declares an "object parameter" (pass by value) and Args&& declares a reference parameter (pass by reference). Passing by reference allows one to avoid copying the argument when that is unnecessary.

What is 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.


2 Answers

It is really quite simple (two live examples, gcc and clang)

template<class...T> void foo(T&&...) {std::cout << "...T\n";}
template<class T> void foo(T&&) {std::cout << "T\n";}
int main() {
  foo(3);
}

Overloads not taking ... seem to be preferred when the choice is an explicit template parameter.

The class=std::enable_if_t does not change this.

So both your functions f are candidates, then the compiler prefers the one without variardics.

14.8.2.4 Deducing template arguments during partial ordering [temp.deduct.partial]

/8:

If A was transformed from a function parameter pack and P is not a parameter pack, type deduction fails. Otherwise, using the resulting types P and A, the deduction is then done as described in 14.8.2.5. If P is a function parameter pack, the type A of each remaining parameter type of the argument template is compared with the type P of the declarator-id of the function parameter pack. Each comparison deduces template arguments for subsequent positions in the template parameter packs expanded by the function parameter pack. If deduction succeeds for a given type, the type from the argument template is considered to be at least as specialized as the type from the parameter template. [ Example:

template<class... Args> void f(Args... args); // #1
template<class T1, class... Args> void f(T1 a1, Args... args); // #2
template<class T1, class T2> void f(T1 a1, T2 a2); // #3
f(); // calls #1
f(1, 2, 3); // calls #2
f(1, 2); // calls #3; non-variadic template #3 is more
// specialized than the variadic templates #1 and #

In particular, the f(1,2) example.

All the enable_if_t clause does is remove the one-argument version from consideration when you pass a std::string as T.

like image 173
Yakk - Adam Nevraumont Avatar answered Sep 22 '22 01:09

Yakk - Adam Nevraumont


Due to the use of the second, enable_if, template parameter in the 'single' version, the compiler considers that version to be a more-specialized template for use with the types for which it is enabled.
It is considered more specialized because there are types where the variadic template can be instantiated, but the 'single' can't.

The general rule is that a more specialized template trumps a less specialized template in overload resolution.

like image 27
Bart van Ingen Schenau Avatar answered Sep 24 '22 01:09

Bart van Ingen Schenau