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

Шаблонный псевдоним и специализация

Предполагая, что

template<typename T> 
struct Foo
{
};

template<typename T> 
struct Bar
{
};

template< template<typename T> class C >
struct Pack
{
    template<typename T>
    using Container = C<T>;
};

Предполагается ли, что Foo и Pack<Foo>::Container рассматриваться как одно и то же, если у нас есть специализация для Foo? То есть:

template< template<typename T> class C >
struct IsFoo : std::false_type
{
};

template<>
struct IsFoo<Foo> : std::true_type
{
};

static_assert( IsFoo<Foo>::value,                             "Only foos!" );
static_assert( IsFoo< Pack<Foo>::Container >::value,          "Only foos!" ); // ???
static_assert( IsFoo< Pack<Bar>::Container >::value == false, "Not a foo!" );

Правильно ли это второе утверждение? Каково ожидаемое поведение? Черт, это то, что я пытаюсь сделать даже действительным?

Я тестировал его на трех компиляторах, и у меня были разные результаты. Кажется, что для MSVC и CLang, Foo и Pack<Foo>::Container - это не одно и то же, но GCC не согласен, что здорово, потому что это именно то, что я хотел.

Итак, кто прав?

PS: Я не уверен, использую ли я правильную терминологию для названия и внутри моего вопроса. Предложения и исправления более чем приветствуются.

4b9b3361

Ответ 1

14.5.7 Шаблоны псевдонимов

1 Объявление шаблона, в котором объявление является декларацией псевдонимов    (Раздел 7) объявляет идентификатор шаблоном псевдонимов. Псевдоним    template - это имя для семейства типов. Имя псевдонима    template - это имя шаблона.

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

В вашем примере Foo и Pack<Foo>::Container (нет списка параметров) являются именами шаблонов, которые не представляют тип, а только шаблон. Например, Foo<int> и Pack<Foo>::Container<int> будут идентификаторами шаблонов и поэтому будут эквивалентны.

Насколько я знаю, стандарт не указывает никакого отношения эквивалентности между именами шаблонов, поэтому MSVC и Clang имеют право предположить, что эквивалентны только идентичные имена шаблонов.

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

template< typename C >
struct IsFoo : std::false_type
{
};

template<class T>
struct IsFoo<Foo<T>> : std::true_type
{
};

static_assert( IsFoo<Foo<int>>::value,                             "Only foos!" );
static_assert( IsFoo< Pack<Foo>::Container<int> >::value,          "Only foos!" );
static_assert( IsFoo< Pack<Bar>::Container<int> >::value == false, "Not a foo!" );

или

template<class T>
void do_stuff(const T&) {}

template<class T>
void do_stuff(const Foo<T>&) {}