C++11: Template argument deduction, partial ordering, and trailing parameter packs

171 views
Skip to first unread message

Christoph Schulz

unread,
Feb 20, 2016, 4:20:10 PM2/20/16
to

Hello,

I read §14.8.2.1, §14.8.2.4, and §14.8.2.5 multiple times but did not find
a convincing argumentation why the second of the following two function
templates is more specialized for the given argument than the first one:

========= %< =========
#include <ostream>
#include <iostream>

template<int ...T>
struct X {};

// #1
template<int I, int ...Ints>
int f(X<I, Ints...> x) {
return I + f(X<Ints...>{});
}

// #2
template<int I>
int f(X<I>) {
return I;
}

int main()
{
std::cout << f(X<1>{}) << std::endl; // selects #2
}
========= %< =========

The compiler I used (g++ 4.9.3) has no problems compiling this code. But
I don't understand why. For both #1 and #2, "I" can be deduced to be "1",
and in #1, "Ints..." can be deduced to be an empty list of int values,
making the parameter type be "X<1>" in both cases. (This can be "proven"
by removing #1 or #2 from the overload set by #if 0 ... #endif, and seeing
the code compile successfully in both cases.) So, according to
§13.3.3/1, partial ordering of function templates should disambiguate this
case. But which rule makes #2 more specialized than #1? In this situation,
§14.8.2.5/9 seems to apply, but the sentence

- if P does not contain a template argument corresponding to Ai then Ai
is ignored;

seems to support the interpretation that #1 can be deduced from #2.

Can anybody shed some light on it? I'm sure that I overlooked
something... Or does g++ behave simply wrong?


Best regards,

--
Christoph Schulz


[ comp.std.c++ is moderated. To submit articles, try posting with your ]
[ newsreader. If that fails, use mailto:std-cpp...@vandevoorde.com ]
[ --- Please see the FAQ before posting. --- ]
[ FAQ: http://www.comeaucomputing.com/csc/faq.html ]

Christof Meerwald

unread,
Mar 16, 2016, 2:10:07 AM3/16/16
to

On Sat, 20 Feb 2016 15:19:09 CST, Christoph Schulz wrote:
>========= %< =========
> #include <ostream>
> #include <iostream>
>
> template<int ...T>
> struct X {};
>
> // #1
> template<int I, int ...Ints>
> int f(X<I, Ints...> x) {
> return I + f(X<Ints...>{});
> }
>
> // #2
> template<int I>
> int f(X<I>) {
> return I;
> }
>
> int main()
> {
> std::cout << f(X<1>{}) << std::endl; // selects #2
> }
>========= %< =========

Isn't that kind of what core issues 1395
http://wg21.cmeerw.net/cwg/issue1395 and 1432
http://wg21.cmeerw.net/cwg/issue1432 are about?

g++ is likely implementing the proposed resolution, but that
resolution hasn't been incorporated into the standard text yet.


Christof


--
http://cmeerw.org sip:cmeerw at cmeerw.org
mailto:cmeerw at cmeerw.org xmpp:cmeerw at cmeerw.org

Christoph Schulz

unread,
Mar 16, 2016, 2:10:16 AM3/16/16
to

Hello!

Christoph Schulz wrote:

> Hello,
>
> I read §14.8.2.1, §14.8.2.4, and §14.8.2.5 multiple times but did not find
> a convincing argumentation why the second of the following two function
> templates is more specialized for the given argument than the first one:
> [...]

I just learned that clang++ (version 3.7.0) barks at the code:

main.cpp:21:18: error: call to 'f' is ambiguous
std::cout << f(X<1>{}) << std::endl; // selects #2
^
main.cpp:9:5: note: candidate function [with I = 1, Ints = <>]
int f(X<I, Ints...> x) {
^
main.cpp:15:5: note: candidate function [with I = 1]
int f(X<I>) {
^
1 error generated.

Perhaps my assumption that this code is ambiguous is indeed correct.
Nevertheless I would like to see it confirmed by some other C++ expert(s)
;-)
Reply all
Reply to author
Forward
0 new messages