Boost logo

Boost :

Subject: Re: [boost] [string_ref] logical ops ambiguity errors (Re: bjam compiler error)
From: Steven Watanabe (watanabesj_at_[hidden])
Date: 2013-02-26 00:28:58


AMDG

On 02/25/2013 05:04 PM, Eric Niebler wrote:
>
> You might be right. This is an interesting case. E.g. the following
> compiles with clang trunk:
>
> template<typename T> struct identity { typedef T type; };
> template<typename T> struct string_ref {};
>
> template<typename T>
> void foo(string_ref<T>, string_ref<T>) {} <---- a
>
> template<typename T>
> void foo(string_ref<T>, typename identity<string_ref<T> >::type) {} <---- b
>
> template<typename T>
> void foo(typename identity<string_ref<T> >::type, string_ref<T>) {} <---- c
>
> int main()
> {
> string_ref<int> ref;
> foo(ref, ref);
> }
>
> Seems to rely on some partial ordering magic, even though all three are
> viable matches and they all yield the same function signature. At any
> rate, MSVC wasn't happy with it. It could be a compiler bug. Probably
> worth investigating and filing.
>

I don't think that this code is legal. (b) and (c)
are obviously equivalent in terms of partial ordering.
Neither is more specialized than the other. Unfortunately,
I can't seem to find any provision for template paramters
used in non-deduced contexts (as described in 14.8.2.5p5).
14.5.6.2 and 14.8.2.4 both appear to assume that
this scenario never occurs. The transformation described in
14.5.6.2p3 is technically impossible to implement in
this case, as the compiler cannot instantiate a template
with the synthesized type. However, I can't come up with
any sensible rule under which (a) is more specialized
than (b). The simplest method (which I've always
assumed to hold) is to treat

template<typename T>
void foo(string_ref<T>, typename identity<string_ref<T> >::type) {}

as if it were

template<typename T>
void foo(string_ref<T>, typename identity<string_ref<char> >::type) {}

in which case it is obvious that (b) should be considered
more specialized than (a).

Or, we could synthesize a unique type to
substitute for identity<string_ref<char> >::type,
in which case template argument deduction fails
in both directions and neither (a) nor (b) is
more specialized than the other.

Or, we could treat it as if it were something like:

template<typename T>
void foo(string_ref<T>, identity___type<string_ref<T> >) {}

(effectively transforming non-deduced contexts into deduced
contexts) In this case, template argument deduction fails in
both directions and neither (a) nor (b) is more specialized
than the other.

The only way I can see this working is if there's actually
some kind of parameter-order dependence in the partial ordering
rules that I missed, which makes (b) more specialized than (c).

In Christ,
Steven Watanabe


Boost list run by bdawes at acm.org, gregod at cs.rpi.edu, cpdaniel at pacbell.net, john at johnmaddock.co.uk