template aliases and sfinae
Asked Answered
C

1

12

In the case of a substitution failure involving a template alias (e.g. a template alias on a missing member typename, as in the code snippet below), should an error be triggered ?

Clang and gcc seem to disagree on this:

// some types
struct bar { };

struct foo {
    typedef void member_type;
};


// template alias
template<class T>
using member = typename T::member_type;


template<class T>
void baz(... ) { }

// only works for gcc, clang fails with: no type named 'member_type'
// in 'bar'
template<class T>
void baz( member<T>* ) { }


int main(int, char** ) {

    baz<bar>(0);            // picks first
    baz<foo>(0);            // picks second

    return 0;
}

So the question is: who is correct, and why ?

Thanks :-)

Chintzy answered 5/12, 2012 at 16:46 Comment(5)
What does clang -v say? Clang 3.3 trunk compiles the code just fine.Electrodynamometer
Debian clang version 3.1-8 here, looks like I just need to wait. Thanks for your feedback !Chintzy
Can you get rid of the template alias, just to simplify things a littleMaxine
@Dave: The whole point of the question was about using aliases, so...Electrodynamometer
@Electrodynamometer oh, sorry. I only looked at the code and thought it was just about SFINAE.Maxine
A
5

According to the Standards, it is clearly GCC that is correct, because the alias template must immediately be replaced and then normal/usual SFINAE is applied to typename T::member_type later when T is known.

But there currently is an issue for this, see http://www.open-std.org/jtc1/sc22/wg21/docs/cwg_active.html#1554.

According to the meetings outcome, it appears that clangs behavior is desired: The substitution of T will be done in the context of the alias template (even though at the time of substitution in typename T::member_type, there is no reference to the alias template anymore - it will still need to be referenced as the source of where the parameter type pattern originated from, if this is how it's implemented).


This is similar to another situation where patterns are thrown away on definition time that could influence instantiation semantics

template<int I>
void f(int x[I]);

int main() {
  f<0>(nullptr);
}

In this case too, in my opinion the Standard normatively is clear that the parameter is immediately being replaced by int* and thus the instantiation works. See http://www.open-std.org/jtc1/sc22/wg21/docs/cwg_active.html#1322 .

Antiserum answered 5/12, 2012 at 19:26 Comment(3)
"According to the meetings outcome, it appears that clangs behavior is desired" -- wouldn't this totally kill any EnableIf alias out there? It seems highly undesirable to have alias templates not generate SFINAE soft-errors.Electrodynamometer
@Electrodynamometer yes that would be bad. And in fact, clang trunk accepts the EnableIf alias, so it appears to me the behavior that the asker observed was just a clang bug, and that the issue's summary on the wg21 site is just confusing (IMHO).Antiserum
Yeah, I was confused since I already commented that the trunk compiles the code fine.Electrodynamometer

© 2022 - 2024 — McMap. All rights reserved.