16

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?

willj
  • 2,991
  • 12
  • 24
  • 1
    Oh. GCC also thinks `sizeof n` is dependent. http://melpon.org/wandbox/permlink/BLobLBzkQXNRfDuq – willj Dec 30 '14 at 22:06
  • Well, `sizeof n` is not type-dependent but value-dependent. `sizeof X`, where `X` is *not* type-dependent is not dependent at all. Hence, `sizeof sizeof n` must be nondependent, no? – dyp Dec 30 '14 at 22:06
  • Interestingly, compiles on gcc 4.7.2, but fails on 4.9.0. – Barry Dec 30 '14 at 22:06
  • @dyp Good point, I've changed the example.. – willj Dec 30 '14 at 22:13
  • @willj How does this change anything? `sizeof( type-id )` is still not type-dependent. – dyp Dec 30 '14 at 22:20
  • @dyp More parenthesis! And `sizeof n` is not value-dependent, while `sizeof(T)` is. This new version requires a second `sizeof()` to no longer be dependent. – willj Dec 30 '14 at 22:24
  • `sizeof( type-id )` is value-dependent, but not type-dependent. `sizeof unary-expression` is dependent IFF the unary-expression is **type**-dependent. The parentheses don't change anything, it's a unaray expression with and without parentheses. (A primary expression can be a parenthesized expression.) – dyp Dec 30 '14 at 22:31
  • You have some typos in your question, swapping type and value. In last paragraph – Yakk - Adam Nevraumont Dec 30 '14 at 22:31

1 Answers1

7

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.

dyp
  • 38,334
  • 13
  • 112
  • 177
  • Good point on the outer set of parentheses. For some reason I'm hard-wired to write `sizeof(expression)` – willj Dec 30 '14 at 22:48