Подтвердить что ты не робот

С++ 1y/С++ 14: Специализация переменных шаблонов?

В соответствии с С++ 1y/С++ 14 N3690, тип специализации шаблона шаблона должен быть таким же, как тип первичного шаблона?

template<int x>
char y = f(x);

template<>
double y<42> = g();

И если да, можно ли как-нибудь оставить основной undefined?

template<int x>
???? y = ???; // undefined

template<>
double y<42> = g();

Где это указано в черновике?

Эквивалентная функциональность для шаблона класса:

template<int x>
struct S
{
    static char y;
};

template<>
struct S<42>
{
    static double y;
};

и

template<int x>
struct S; // undefined

template<>
struct S<42>
{
    static double y;
};
4b9b3361

Ответ 1

Означает ли тип специализации шаблона так же, как тип первичного шаблона?

Нет, явная (или частичная) специализация шаблона переменной может указывать тип, отличный от типа, который подразумевается неявным экземпляром. При реализации функции для Clang мы обнаружили, что спецификация не имела правила, требующего соответствия типа в этом случае, и мы привели проблему в рабочую группу ядра С++, где было подтверждено, что это упущение было преднамеренным.

Можно ли как-то оставить основной undefined?

Невозможно объявить основной шаблон переменной без указания типа - нет синтаксиса, который позволил бы такую ​​вещь.

Где это указано в черновике?

Оба из них охватываются бездействием - нет правила, требующего соответствия типов, и нет синтаксиса для объявления шаблона переменной без типа. Поэтому я не могу указать вам на какую-либо конкретную часть стандарта и сказать "здесь, где правило не является".

Если у вас есть доступ к рефлекторам стандартного комитета С++, см. поток, начинающийся с core-23901, для обсуждения этого вопроса.

Ответ 2

Следующие компиляции с clang trunk -std=c++1y:

#include <iostream>

template<int x>
char y = 3;

template<>
double y<42> = 2.5;

char c {y<17>};

double d {y<42>};

Таким образом, либо специализация шаблона переменной не должна иметь тот же тип, что и ее основной, или clang имеет ошибочную реализацию N3690

Ответ 3

Я бы полностью ожидал, что объявление специализации должно точно соответствовать основному шаблону, включая его тип. Это не ново для переменных шаблонов. Я не преследовал детали в стандарте, но, чтобы увидеть, где он указывает эту деталь.

Нижеприведенный код делает что-то похожее на то, что вам нужно, т.е. оставить тип переменной типа открытым:

#include <iostream>

template <int X> struct var_type { typedef int type; };
template <> struct var_type<42> { typedef double type; };

int    f(int x) { return x; }
double g()    { return 3.14; }

template <int X>
typename var_type<X>::type var = f(X);
template <>
typename var_type<42>::type var<42> = g();

int main()
{
    std::cout << "var<17>=" << var<17> << '\n';
    std::cout << "var<42>=" << var<42> << '\n';
}

Ответ 4

Немного рискованно экстраполировать, что Кланг выражает функцию, предназначенную для стандартизации. (NB: я не ссылался ни на что для этого ответа.)

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

Вы всегда можете использовать шаблон типа для объявления типа шаблона переменной.

template< typename t >
struct x_type { typedef … type; };

template< typename t >
typename x_type< t >::type x = …;

Теперь x_type может быть специализированным. Это просто защищает от возможности, что Кланг в настоящее время не работает. Это не позволяет ссылаться на объект неопределенного типа. С++ просто не поддерживает это. Ссылаясь на объект ODR - использует специализацию шаблона класса.