Re: Variadic templates and overload resolution
On Jan 8, 8:37 pm, "Piotr Wyderski"
<piotr.wyder...@mothers.against.spam.gmail.com> wrote:
The following program:
#include <utility>
#include <cstdio>
template <typename T, typename... TA> T fn(TA&&... args) {
fprintf(stderr, "T fn(TA&&... args)\n");
return 0;
};
template <typename T, typename... TA> void fn(T& v, TA&&... args) {
fprintf(stderr, "void fn(T& v, TA&&... args)\n");
v = fn<T>(std::forward<TA>(args)...);
};
int main(int argc, char *argv[]) {
long j = 0;
int i = 0;
fn<int>();
fprintf(stderr, "\n");
fn(i);
fprintf(stderr, "\n");
fn<int>(j);
fprintf(stderr, "\n");
fn(i, j);
fprintf(stderr, "\n");
return 0;
}
compiled with the newest GCC-4.5-trunk prints:
$ a
T fn(TA&&... args)
void fn(T& v, TA&&... args)
T fn(TA&&... args)
T fn(TA&&... args)
void fn(T& v, TA&&... args)
T fn(TA&&... args)
That is intended behaviour, but... why does it work the way it works?
Which standard/draft rules specify that the fn() overloads are matched
in a way the program's output indicates?
I haven't checked the standard for chapter and verse, but the relevant
rules are as follows:
i. An overload which does not require a conversion is preferred over
one which does.
ii. A more specialized overload is preferred over a less specialized
one.
Rule i is stronger. Rule ii is only used where rule i does not apply.
The definition of "more specialized" is basically as follows: If any
set of parameters which is legal for overload A is also legal for
overload B, and there also exists a set of parameters which is legal
for overload B but not for overload A, overload A is more specialized.
In other words an overload is more specialized if it can be applied in
fewer situations.
Given your two functions:
template <typename T, typename... TA> T fn(TA&&... args); // (1)
template <typename T, typename... TA> void fn(T& v, TA&&... args); //
(2)
(2) is more specialized than (1) because it cannot be called with 0
parameters, whereas either function can be called with any set of 1 or
more parameters.
fn<int>();
cannot match (2) because (2) requires at least one parameter, so (1)
is called.
fn(i);
could match either, so it resolves to (2) which is more specialized.
fn<int>(j);
could match either, but (2) would require a conversion (j is a long)
so (1) is preferred.
fn(i, j);
could match either, so it resolves to (2) which is more specialized.
Yechezkel Mett
--
[ See http://www.gotw.ca/resources/clcm.htm for info about ]
[ comp.lang.c++.moderated. First time posters: Do this! ]