8

The following code is from http://www.pvv.org/~oma/PubQuiz_ACCU_Apr2014.pdf (#6, solution on page 34). The goal was to guess the output for the following.

#include <iostream>
template <template <typename> class>
struct X {
    X() { std::cout << "1"; }
};

template<typename >
struct Y {};

template<typename T>
using Z = Y<T>;

template<>
struct X<Y> {
    X() { std::cout << "2"; }
};

int main() {
    X<Y> x1;
    X<Z> x2;
}

The answer can be found on page 34. I don’t understand the second case with the alias template, why the primary template is chosen for X<Z> instead of the fully specialized.

The correct answer should be "21" as written in the presentaton. My MinGW (gcc 5.1) prints "22" and http://ideone.com (which uses gcc 4.9.2) also prints "22". Clang from a friend on MacOS X prints "21". So I guess this is a bug in gcc.

Can anyone explain to me why "1" is printed for the X<Z> and what paragraph from the standard gcc might failed to implement or not yet implemented?

bugybunny
  • 544
  • 5
  • 13
  • 7
    Bear in mind that, in the context of the quiz, "correct" doesn't mean "what the standard says", it means "what happened on the quizmaster's machine". So it could be that either, both, or neither compiler is compliant here. – Mike Seymour May 14 '15 at 17:05
  • Yeah ok. I guessed clang implements it correctly but that’s only my guess. And I don’t think that he chose something with undefined behavior for the quiz. – bugybunny May 14 '15 at 17:09
  • I can't actually find anything. If `Y` were a simple type and `Z` aliased it, we'd print 22. Would be fairly inconsistent to print 21 here then. Clearly `Y` and `Z` are the same type. – Barry May 14 '15 at 17:10
  • 6
    This is an [active CWG issue](http://www.open-std.org/jtc1/sc22/wg21/docs/cwg_active.html#1286). – T.C. May 14 '15 at 17:30

1 Answers1

4

I think it is

14.5.7 Alias templates

1 A template-declaration in which the declaration is an alias-declaration (Clause 7) declares the identifier to be a alias template. An alias template is a name for a family of types. The name of the alias template is a template-name.

The above means that Y and Z are different template-names, so they are different templates. What might confuse you/the compiler is that Y<T> and Z<T> will always yield an identical type.

Consider:

#include <type_traits>

template <typename>
struct W {};

template <template <typename> class>
struct X {};

template<typename>
struct Y {};

template<typename T>
using Z = Y<T>;

int main()
{
    static_assert( std::is_same< Y<int>, Z<int> >::value, "Oops" );
    static_assert( std::is_same< W<Y<int>>, W<Z<int>> >::value, "Oops" );
    static_assert( ! std::is_same< X<Y>, X<Z> >::value, "Oops" );
}

Live example

The above works for Clang, but not for GCC.

EDIT: As pointed out by @T.C. there is an active CWG issue 1286 which suggests that Clang is doing what the standard currently says, but not what was intended.

Daniel Frey
  • 55,810
  • 13
  • 122
  • 180