problem with partial ordering of classes

R

Rodolfo Lima

Hi, I'm having some problems with the following code, gcc-4.5 refuses
to compile it:

#include <iostream>

template <bool B, class V=void> struct enable_if {};
template <class V> struct enable_if<true,V> { typedef V type; };

template <class T>
struct bar {};

template <class T, int ID, class V=void>
struct foo;

template<template<class> class V, class T, int ID>
struct foo<V<T>, ID>
{
static const int value = 1;
};

template<class T, int ID>
struct foo<bar<T>,ID, typename enable_if<ID!=0>::type>
{
static const int value = 2;
};

int main()
{
std::cout << foo<bar<int>,1>::value << std::endl;
}

//------------------------------------------


The error message:
teste.cpp: In function ‘int main()’:
teste.cpp:26:30: error: ambiguous class template instantiation for
‘struct foo<bar<int>, 1>’
teste.cpp:14:1: error: candidates are: struct foo<V<T>, ID>
teste.cpp:20:1: error: struct foo<bar<T>, ID, typename
enable_if<(ID != 0)>::type>
teste.cpp:26:15: error: incomplete type ‘foo<bar<int>, 1>’ used in
nested name specifier

According to partial ordering rules, struct foo<bar<T>,ID, typename
enable_if<ID!=0>::type> is more specialized than struct foo<V<T>, ID>,
isn't it? So it should be used, instead of giving an ambiguity error.

Am I wrong or is the compiler?

Regards,
Rodolfo Lima
 
P

Paul Bibbings

Rodolfo Lima said:
Hi, I'm having some problems with the following code, gcc-4.5 refuses
to compile it:

#include <iostream>

template <bool B, class V=void> struct enable_if {};
template <class V> struct enable_if<true,V> { typedef V type; };

template <class T>
struct bar {};

template <class T, int ID, class V=void>
struct foo;

template<template<class> class V, class T, int ID>
struct foo<V<T>, ID>
{
static const int value = 1;
};

template<class T, int ID>
struct foo<bar<T>,ID, typename enable_if<ID!=0>::type>
{
static const int value = 2;
};

int main()
{
std::cout << foo<bar<int>,1>::value << std::endl;
}

//------------------------------------------


The error message:
teste.cpp: In function ¡®int main()¡¯:
teste.cpp:26:30: error: ambiguous class template instantiation for
¡®struct foo<bar<int>, 1>¡¯
teste.cpp:14:1: error: candidates are: struct foo<V<T>, ID>
teste.cpp:20:1: error: struct foo<bar<T>, ID, typename
enable_if<(ID != 0)>::type>
teste.cpp:26:15: error: incomplete type ¡®foo<bar<int>, 1>¡¯ used in
nested name specifier

According to partial ordering rules, struct foo<bar<T>,ID, typename
enable_if<ID!=0>::type> is more specialized than struct foo<V<T>, ID>,
isn't it? So it should be used, instead of giving an ambiguity error.

This is interesting, and I only wish that I had the answer (which I
don't). What intrigues me, however, is that the rules of partial
ordering nevertheless are able to lead to a successful selection if your
first partial specialization of foo is likewise augmented to avoid
making use of the default template argument provided by the primary
template. That is, if we replace your:

template<template<class> class V, class T, int ID>
struct foo<V<T>, ID>
{
static const int value = 1;
};

with:

template<template<class> class V, class T, int ID>
struct foo<V<T>, ID, typename enable_if<ID!=0>::type>
{
static const int value = 1;
}

then your /second/ partial specialization, for which
foo<bar<int>,1>::value == 2, is selected as more specialized than the
first. (And note, that the code likewise works if *both*
specializations make use of this same default.) But then, what is going
on here? How is it that the viability of this second specialization as
preferred over the first thus augmented is suddenly undermined simply
when, as in your original code, this first is allowed to make use of the
default?

All that I can think of is that it might come down to an interpretation
of a note tucked away in [temp.deduct.type] ¡ì14.8.2.4/18:

"[Note: a default /template-argument/ cannot be specified in a function
template declaration or definition; therefore default
/template-argument/s cannot be used to influence template argument
deduction. ]"

which might be made to relate to the partial ordering of class template
partial specializations through the requirements of [temp.class.order]
¡ì14.5.4.2, for which the process involves the transformation of each
partial specialization into an appropriate function template, before
applying the rules of template argument deduction in the way
prescribed.

I have to admit that I have never fully followed through my
understanding (or lack of it) of the above-quoted note. However, it
looks almost as if gcc is taking this and saying something like "If
either both, or neither, of the partial specialization make use of the
default, then we can order this. However, if only one of them does then
that can be seen as an attempt to 'influence template argument
deduction' through use of a default template argument, and so we'll let
them both go, and leave it ambiguous." But that seems like nonsense,
and I can't believe that gcc is doing any such thing.

So. Like I said. Dunno!

Regards

Paul Bibbings
 
P

Paul Bibbings

Rodolfo Lima said:
Hi, I'm having some problems with the following code, gcc-4.5 refuses
to compile it:

#include <iostream>

template <bool B, class V=void> struct enable_if {};
template <class V> struct enable_if<true,V> { typedef V type; };

template <class T>
struct bar {};

template <class T, int ID, class V=void>
struct foo;

template<template<class> class V, class T, int ID>
struct foo<V<T>, ID>
{
static const int value = 1;
};

template<class T, int ID>
struct foo<bar<T>,ID, typename enable_if<ID!=0>::type>
{
static const int value = 2;
};

int main()
{
std::cout << foo<bar<int>,1>::value << std::endl;
}

//------------------------------------------


The error message:
teste.cpp: In function ¡®int main()¡¯:
teste.cpp:26:30: error: ambiguous class template instantiation for
¡®struct foo<bar<int>, 1>¡¯
teste.cpp:14:1: error: candidates are: struct foo<V<T>, ID>
teste.cpp:20:1: error: struct foo<bar<T>, ID, typename
enable_if<(ID != 0)>::type>
teste.cpp:26:15: error: incomplete type ¡®foo<bar<int>, 1>¡¯ used in
nested name specifier

According to partial ordering rules, struct foo<bar<T>,ID, typename
enable_if<ID!=0>::type> is more specialized than struct foo<V<T>, ID>,
isn't it? So it should be used, instead of giving an ambiguity error.

For the record, Comeau agrees with gcc-4.5 here:

Comeau C/C++ 4.3.10.1 (Oct 6 2008 11:28:09) for
ONLINE_EVALUATION_BETA2
Copyright 1988-2008 Comeau Computing. All rights reserved.
MODE:strict errors C++ noC++0x_extensions

"ComeauTest.c", line 46: error: more than one partial specialization
matches the template argument list of class "foo<bar<int>, 1,
void>"
"foo<V<T>, ID, void>"
"foo<bar<T>, ID, enable_if<<expression>, void>::type>"
std::cout << foo<bar<int>,1>::value << std::endl;
^
1 error detected in the compilation of "ComeauTest.c".
In strict mode, with -tused, Compile failed
Hit the Back Button to review your code and compile options.
Compiled with C++0x extensions DISabled.

Regards

Paul Bibbings
 
R

Rodolfo Lima

It seems I was wrong after all.
See this thread:
http://groups.google.com/group/comp.lang.c++.moderated/browse_frm/thread/32d9c5f5e5f6d0be/

In a nutshell (just for the record), the partial specialization

template<class T, int ID>
struct foo<bar<T>,ID, typename enable_if<ID!=0>::type>

can't be defined because the last argument falls into non-deducible
context (according to 14.8.2.4 [temp.deduct.type]). There's a core
issue about requiring this to be ill-formed.

[]s,
rod

PS: I really admire who understands/knows all of 14.8.2 [temp.deduct]
 
P

Paul Bibbings

It seems I was wrong after all.
See this thread:http://groups.google.com/group/comp.lang.c++.moderated/browse_frm/thr...

In a nutshell (just for the record), the partial specialization

template<class T, int ID>
struct foo<bar<T>,ID, typename enable_if<ID!=0>::type>

can't be defined because the last argument falls into non-deducible
context (according to 14.8.2.4 [temp.deduct.type]). There's a core
issue about requiring this to be ill-formed.

[]s,
rod

PS: I really admire who understands/knows all of 14.8.2 [temp.deduct]

I am not sure that I agree with this analysis, for essentially the
reasons that Johannes Schaub has tentatively added in his follow-up
post in c.l.c++.m. Note, as Johannes points out, that the last
argument
is not required to be a deduced-context, as ID is deduceable from the
second argument.

http://www.open-std.org/jtc1/sc22/wg21/docs/cwg_active.html#455 (as
referenced by Daniel Krugler) seems a much more likely avenue to
pursue
in understanding what's at issue here.

Regards

Paul Bibbings
 

Ask a Question

Want to reply to this thread or ask your own question?

You'll need to choose a username for the site, which only take a couple of moments. After that, you can post your question and our members will help you out.

Ask a Question

Members online

Forum statistics

Threads
473,962
Messages
2,570,134
Members
46,690
Latest member
MacGyver

Latest Threads

Top