Странное поведение is_same_template для псевдонимов шаблонов

Следующая программа...

#include <iostream>
#include <type_traits>

template <typename T>
struct Template{};

template <typename T>
using Alias = Template<T>;

template
    <
        template <typename>
        class T1,
        template <typename>
        class T2
    >
struct is_same_template : std::false_type{};

template
    <
        template <typename>
        class T
    >
struct is_same_template<T, T> : std::true_type{};

int main() {
    std::cout << std::boolalpha;
    std::cout << "Template == Template: " << is_same_template<Template, Template>::value << std::endl;
    std::cout << "Template == Alias: " << is_same_template<Template, Alias>::value << std::endl;
    std::cout << "Alias == Alias: " << is_same_template<Alias, Alias>::value << std::endl;
}

...выводит...

Template == Template: true
Template == Alias: false
Alias == Alias: true

...скомпилировано с помощью g++ 4.8.1, clang 3.4 и vc++ 18.00.21005.1.

Это ошибка в этих компиляторах или требование стандарта?


person Constructor    schedule 06.04.2014    source источник
comment
Каков ваш ожидаемый результат?   -  person John Zwinck    schedule 06.04.2014
comment
@JohnZwinck true/true/true, конечно, как и для псевдонимов типов и std::is_same.   -  person Constructor    schedule 06.04.2014
comment
Попробуйте добавить ... к typename в вашем is_same_template. Теперь добавьте template<T,U>foo и bar<T>=foo<T,T>. Что должно произойти с is_same_template<foo,bar>?   -  person Yakk - Adam Nevraumont    schedule 06.04.2014
comment
@Yakk Я думаю, что в этом случае программа должна выводить false (и это так). Но в шаблонах вашего примера количество аргументов шаблона и его псевдонима даже не равны. Как они могут быть эквивалентны в таком случае? Что вы имеете в виду здесь?   -  person Constructor    schedule 06.04.2014
comment
Меня это не удивляет... только специализации шаблона псевдонимов являются псевдонимами типов. Сам шаблон псевдонима является отдельным шаблоном. См. [temp.alias] и обсуждение в оригинальное предложение   -  person dyp    schedule 06.04.2014
comment
@dyp Спасибо за эту ссылку. Насколько я понимаю, первый вариант шаблонов псевдонимов был выбран в стандарте C++11 (но без возможности специализации шаблонов псевдонимов). Но я не могу найти точное место в стандарте, где это поведение явно указано (даже в абзаце [temp.alias]). Вы имеете в виду это предложение: «Имя шаблона псевдонима — это template-name»?   -  person Constructor    schedule 06.04.2014
comment
Я не думаю, что это указано явно. Но нет правила, согласно которому при некоторых обстоятельствах шаблон псевдонима должен быть псевдонимом шаблона (то есть другим именем шаблона класса). Рассмотрим template<class T> using vec = std::vector<T>; (это псевдоним шаблона?) или template<class T> using Templ = Template<T*>; (это псевдоним шаблона?). Для указания именно тех случаев, когда шаблон псевдонима является псевдонимом шаблона, потребуется специальное правило.   -  person dyp    schedule 06.04.2014
comment
@dyp Большое спасибо за объяснение! Теперь я вижу, вы, вероятно, правы, что нет специального правила для точных шаблонных синонимов. И ваша ссылка очень интересна. Еще раз спасибо!   -  person Constructor    schedule 06.04.2014
comment
Не за что :) IIRC уже было несколько дискуссий по этой теме на SO, но я не уверен, что искать, чтобы их найти.   -  person dyp    schedule 06.04.2014
comment
@dyp Могу ли я задать вопрос о вашем ответить на упомянутый вопрос?   -  person Constructor    schedule 06.04.2014
comment
Я отозвал эту ссылку (= удалил комментарий), когда понял, что это другой аспект шаблонов псевдонимов ;) Конечно, вы можете задать вопрос, предпочтительно в качестве комментария к этому ответ (или как новый вопрос SO).   -  person dyp    schedule 06.04.2014


Ответы (1)


Таково поведение, требуемое Стандартом, и оно совершенно логично. Шаблон псевдонима не псевдоним шаблона (несмотря на то, что некоторые так считают). Первоначально даже в Стандарте существовала некоторая путаница по этому поводу, см. http://www.open-std.org/jtc1/sc22/wg21/docs/cwg_defects.html#1244 .

В текущей стандартизированной форме шаблон псевдонима похож на свою нешаблонную копию: он создает псевдоним типа. В шаблонной версии тип может быть зависимым.

И тут же подменяется. Например, Alias<T> с T, являющимся параметром шаблона, будет зависимым типом Template<T> — в этом смысле имя шаблон псевдонима может немного сбивать с толку, поскольку предполагает, что в какой-то момент будет создано объявление псевдонима. . Но на самом деле шаблон псевдонима заменяется немедленно — в этом смысле шаблонная версия больше похожа на зависимое объявление псевдонима, которое всегда существует и не нуждается в инстанцировании, а не является шаблоном объявления псевдонима.

Однако с этой точки зрения становится немного философски то, что именно мы подразумеваем под этими терминами.

person Johannes Schaub - litb    schedule 06.04.2014
comment
Спасибо. Отсюда вывод, что в текущей версии стандарта отсутствует полный аналог typedef для шаблонов (я имею в виду простые случаи типа точных синонимов шаблонов, вроде template <typename T> using Alias = Template<T>;), не так ли? Есть ли известное решение этой проблемы? - person Constructor; 06.04.2014
comment
@Constructor нет обходного пути. Вы можете запросить псевдонимы шаблонов, такие как using Alias = Template;, в стандартных предложениях, если хотите их иметь. - person Johannes Schaub - litb; 06.04.2014
comment
Грустно. Ваше предложение интересно. Я постараюсь это реализовать. - person Constructor; 06.04.2014