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

Параметры шаблона шаблона и ссылки пересылки

Предположим, что у нас есть следующий код:

template<typename T>
class C
{};

template <typename T, template <typename> class Container>
void dummyMe(Container<T>&&)
{};

int main(int argc, char* argv[])
{
    C<int> c;
    dummyMe(c);
    return 0;
}

Что не скомпилируется из-за первого аргумента dummyMe, являющегося ссылкой rvalue. Может ли кто-нибудь объяснить мне в Standardese, почему параметры шаблона шаблона не совпадают с ссылками на пересылку и почему это так на простом английском языке.

P.S. Я наткнулся на этот и что, но я не вижу реальных доказательств в ответах.


Ответ по приведенной выше ссылке и ответ на этот вопрос утверждают, что Container<T> нельзя считать параметром шаблона. И я не вижу причин, почему это так. Пусть сделать пример еще проще:

template <template <typename=int> class Container>
void dummyMe(Container<>&&)
{};

Теперь у нас есть пример, почти идентичный следующему:

template <typename Container>
void dummyMe(Container&&)
{};

Но это трактуется совершенно по-другому. Зачем? Почему Container<>&& нельзя считать одним и тем же с template <typename=int> class Container как Container&& до typename Container?

4b9b3361

Ответ 1

Ответ по приведенной выше ссылке и ответ на этот вопрос утверждают, что Container<T> нельзя считать параметром шаблона

То, что является или не является параметром шаблона, не подвержено большой интерпретации. Он четко определен в [temp.param]:

template-parameter: 
    type-parameter 
    parameter-declaration 
 type-parameter: 
    type-parameter-key ...(opt) identier (opt)
    type-parameter-key identier(opt) = type-id 
    template < template-parameter-list > type-parameter-key ...(opt) identier(opt)
    template < template-parameter-list > type-parameter-key identier(opt) = id-expression 
type-parameter-key: 
    class
    typename

Из этих правил производства ясно, что dummyMe имеет ровно два параметра шаблона: typename T и template <typename> class Container. Идентификаторы, которые называют каждый из этих параметров, являются T и Container. T обозначает первый параметр, а Container - второй. Container<T> не является идентификатором и не называет ни одного из двух.

Ответ 2

Термин "ссылка на пересылку" описывается в [temp.deduct.call/3] (из проекта С++ 17 draft n4659):

Ссылка на пересылку - это ссылка rvalue на cv-unqualified параметр шаблона, который не является параметром шаблона шаблон класса (при выводе аргумента шаблона шаблона).

В вашем примере Container<T> не является параметром шаблона, это тип, который вы указали из параметров шаблона T и Container. Чтобы ссылка действительно была переадресована, вы можете использовать только T&&. Пока Conatiner является параметром шаблона, вы не можете ссылаться на шаблон (в вышеприведенных абзацах даже упоминается его явно). Тип Container<T> не совпадает с шаблоном Container. Это экземпляр класса. 1

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

template <typename T, template <typename> class Container>
void dummyMe(Container<T>&&)
{}

template <typename T, template <typename> class Container>
void dummyMe(Container<T>&)
{}

<суб > 1[temp.spec/2] - Класс, созданный из шаблона класса, называется экземпляром класса Суб >