I noticed that gcc 5.0 rejects the following code, while clang 3.6 accepts it.
template<int n>
struct I
{
typedef int Type;
};
template<typename T>
struct A
{
typedef I<sizeof(sizeof(T))>::Type Type;
};
The two compilers seem to differ on whether sizeof(sizeof(T)) is a type-dependent or value-dependent expression. If the expression were dependent, then it follows that I<sizeof(sizeof(T))> is a dependent type, meaning that typename should be required.
This is covered by the following wording in the C++11 standard:
[temp.dep.type]/8
A type is dependent if it is
- a simple-template-id in which either the template name is a template parameter or any of the template arguments is a dependent type or an expression that is type-dependent or value-dependent
[temp.dep.expr]/4
Expressions of the following forms are never type-dependent (because the type of the expression cannot be dependent):
sizeof unary-expression sizeof ( type-id )[temp.dep.constexpr]/2
Expressions of the following form are value-dependent if the unary-expression or expression is typedependent or the type-id is dependent:
sizeof unary-expression sizeof ( type-id )
My interpretation is that sizeof(T) can never be type-dependent, meaning sizeof(sizeof(T)) can never be type-dependent or value-dependent.
Is this a bug in gcc?
I'm using a post-N4296 draft.
typedef I<sizeof(sizeof(T))>::Type Type;
typename is required if the nested-name-specifier I<..> depends on a template parameter [temp.res]/5. So, is I<..> dependent?
[temp.dep.type]/9 A type is dependent if it is
- [...]
- (9.7) a simple-template-id in which either the template name is a template parameter or any of the template arguments is a dependent type or an expression that is type-dependent or value-dependent, or [...]
I<..> is a simple-template-id, the template argument is an expression. Is this expression sizeof(sizeof(T)) type-dependent or value-dependent?
The expression sizeof(sizeof(T)) can be broken down into the following expressions:
expression form
===============================================
T type-id
sizeof(T) sizeof ( type-id )
(sizeof(T)) ( expression )
sizeof(sizeof(T)) sizeof unary-expression
T is not an expression, but I'll leave it in the list for later. A note on the parentheses: A primary-expression can be a parenthesized (general) expression. A unary-expression can be a postfix-expression which can be a primary-expression, hence it can be parenthesized, too.
A parenthesized expression (X) is dependent if X is dependent:
[temp.dep.expr]/1 Except as described below, an expression is type-dependent if any subexpression is type-dependent.
[temp.dep.constexpr]/1 Except as described below, a constant expression is value-dependent if any subexpression is value-dependent.
In general, sizeof expressions are never type-dependent, because they always produce a value of type std::size_t:
[temp.dep.expr]/4 Expressions of the following forms are never type-dependent (because the type of the expression cannot be dependent):
[...] sizeof unary-expression sizeof ( type-id )
However, the value they yield can be dependent on a template parameter:
[temp.dep.constexpr]/2 Expressions of the following form are value-dependent if the unary-expression or expression is type-dependent or the type-id is dependent:
sizeof unary-expression sizeof ( type-id )
expression form value-dep? type-dep?
=======================================================================
T type-id no yes
sizeof(T) sizeof ( type-id ) yes no
(sizeof(T)) ( expression ) yes no
sizeof(sizeof(T)) sizeof unary-expression no no
Since T is type-dependent, sizeof(T) becomes value-dependent. However, since (sizeof(T)) is not type-dependent, sizeof(sizeof(T)) is not dependent at all.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With