Sizeof класса шаблона

template<int N>
struct S
{
    void foo()
    {
        sizeof( S ); // (*)
        sizeof( S<N> );
    }
};

int main()
{
    S<5> s;
    s.foo();
    return 0;
}

Этот код компилируется отлично (VS2010), но я сомневаюсь в строке (*). S не является полным типом, в отличие от S<N>, на мой взгляд, тогда как компилятор знает свой размер? Что говорит стандарт о такой ситуации, правильно ли он сформирован правильно sizeof?

Ответ 1

Имя S внутри определения struct S относится к имени введенного класса S, которое согласно 14.6.1/2 (С++ 03) не требует явного списка аргументов

В рамках специализации шаблона класса или частичного специализации, когда имя введенного класса     не сопровождаемый символом <, он эквивалентен имени введенного класса а затем шаблонные аргументы     специализация шаблона класса или частичная специализация, заключенная в < > .

Обратите внимание, что если вы намеренно вынуждаете компилятор использовать "оригинальное" имя шаблона (вместо введенного имени класса) с помощью оператора разрешения области, список параметров станет обязательным

template<int N>
struct S
{
    void foo()
    {
        sizeof( ::S );    // <- ERROR
        sizeof( ::S<N> ); // <- OK
    }
};

Ответ 2

С++ неявно вставляет using S = S<N>; в тело класса, поэтому оба утверждения эквивалентны.

template<int N>
struct S {
    static_assert(std::is_same<S, S<N>>(), "");
};

Это была бы ошибка, если бы вы сделали sizeof(S) вне определения S.

Ответ 3

В шаблоне имя шаблона также является введенным именем класса и относится к типу класса S<N>, а не к шаблону; и внутри функции члена класса тип класса завершен, даже если функция определена внутри класса. Таким образом, оба действительны и эквивалентны друг другу.

Ответ 4

Функции-члены шаблонов классов не создаются до их вызова. К этому времени класс уже будет создан, и компилятор получит всю необходимую ему информацию для расчета его размера.