C++11 template alias as template template argument leads to different type?
Asked Answered
N

2

9

We have observed a strange behaviour in the compilation of the follwing source code:

template<template<class> class TT> struct X { };
template<class> struct Y { };
template<class T> using Z = Y<T>;

int main() {
  X<Y> y;
  X<Z> z;
  z = y; // it fails here
}

This is a slightly modified example taken from the c++11 standard proposal for template aliases: http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2007/n2258.pdf (See page 4) Also note that the proposal "declares y and z to be of the same type." In our interpretation it should therefore be possible to assign (or copy construct) z from y.

However, this code doesn't compile with gcc 4.8.1 nor with clang 3.3. Is this an error in the compiler or did we misunderstand the standard?

Thanks in advance, craffael et al ;)

P.S. The Clang error message is:

error: no viable overloaded '='

note: candidate function (the implicit copy assignment operator) not viable: no known conversion from 'X<template Y>' to 'const X<template Z>' for 1st argument
template<template<class> class TT> struct X { };

note: candidate function (the implicit move assignment operator) not viable: no known conversion from 'X<template Y>' to 'X<template Z>' for 1st argument
template<template<class> class TT> struct X { };
Nauseating answered 11/10, 2013 at 9:4 Comment(1)
Y and Z are different template-names, as such they yield different instantiations with X. See §14.5.7/1.Ligialignaloes
W
11

The current standard doesn't say so, but the intention is that y and z have the same type. There is an open Core Working Group issue for this: http://wg21.cmeerw.net/cwg/issue1286

Winglet answered 11/10, 2013 at 10:22 Comment(5)
Thanks very much, that was indeed the missing key. I was just scanning the standard right and couldn't really find a hint that my code is ill-formed. However I noted that the example from the Proposal was changed slightly to the one that Daniel Frey suggested. This kind of hints that my code is probably ill formed but it doesn't say so explicitly (this is my interpretation) Anyway I really hope issue 1286 makes it into the next standard...Nauseating
+1 Interesting, so my answer was correct but this is (hopefully) going to change. Good to know!Phototransistor
In issue 1244 it was noticed that there was no wording to support that example, so the Core Working Group updated the example. However, Gaby Dos Reis then commented that the intention really was for the original example to be well-formed, so issue 1286 was opened to update the normative text (and change the example back).Winglet
I hope that after this they make it so that f == g given int f(int x) { return g(x); } and int g(int).Sustenance
@R.MartinhoFernandes: That sort of “mandatory inlining” would change the semantics in complicated cases and would prevent ABI-compatible refactoring.Metaphysic
P
3

I think you are confusing a type and a template (or a template alias). You have Y, which is one template and Z, which is another one. If you think that Y == Z, you are wrong. Only if you turn them into types, those types are the same, e.g. Y<int> is the same type as Z<int>. In your example:

template<class T> struct X { };

template<class> struct Y { };
template<class T> using Z = Y<T>;

int main() {
  X<Y<int>> y;
  X<Z<int>> z;
  z = y; // works
}

In your original code you referred to them with X<Y> and X<Z>, but as Y is not the same as Z, so are X<Y> and X<Z> different types.

Phototransistor answered 11/10, 2013 at 9:11 Comment(1)
I'm aware that types and template's are not the same and I completly agree that your example should compile. However it seems to be unclear from the standard whether my code is ill-formed (see answer of cmeerw).Nauseating

© 2022 - 2024 — McMap. All rights reserved.