Параметр шаблона C ++ - PullRequest
       1

Параметр шаблона C ++

0 голосов
/ 14 октября 2018
#include <iostream>

using namespace std;

template <typename T = int>
struct Foo {
    T t;
    Foo() { cout << "Foo" << endl; }
};

template <typename T>
struct Baz {
    T t;
    Baz() { cout << "Baz" << endl; }
};

template <typename T>
struct Bar {
    T t;
    Bar() { cout << "Bar" << endl; }
};

template <template <typename X> class T>
struct Bar {
    T data;
    Bar() : data() { cout << "Bar" << endl; }
};

int main()
{
    Bar<Foo<>> a;

    Bar<Baz<float>> b;

    Bar<int> c;

    return 0;
}

Я только начинаю изучать шаблоны.И я действительно запутался с параметрами шаблона шаблона.Я понимаю, что вы передаете шаблон в качестве аргумента.В моем классе шаблонов для Bar, где он получает аргумент шаблона шаблона, что представляет <typename X>?Является ли typename X параметром шаблона для class T?

template <template <typename X> class T>
struct Bar {
    T data;
    Bar() : data() { cout << "Bar" << endl; }
};

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

Ответы [ 2 ]

0 голосов
/ 14 октября 2018

Параметры шаблона шаблона позволяют передавать шаблоны в другие шаблоны.Они не являются конкретными типами и должны быть параметризованы для их усиления.

В моем классе шаблонов для Bar, где он получает аргумент шаблона шаблона, что представляет <typename X>?

Из стандартного [basic.scope.temp] ;

Декларативная область имени параметра шаблона шаблона-параметра шаблона является наименьшим списком параметров шаблона, в котором было введено имя.

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

Однако пример, когда полезно дать ему имя, этоесли от него зависит другой параметр шаблона нетипичного типа.Для пример , template <template <typename X, X> typename Y>.

Что касается вашего примера кода, у вас есть две проблемы со вторым объявлением Bar.Во-первых, Bar уже объявлен для принятия типа, а не шаблона.Ваше второе объявление вступает в противоречие, так как оно объявлено для принятия шаблона.

Здесь вам требуется специализация Bar, где специализация разрешается в один тип, соответствующий первичному шаблону.Например,

template <template <typename> class T,typename Y>
struct Bar<T<Y>> {
    T<Y> data;
    Bar() : data() { cout << "Bar" << endl; }
};

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

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

Вот рабочий пример вашего кода со специализацией Bar.

#include <iostream>

using namespace std;

template <typename T = int>
struct Foo {
    T t;
    Foo() { cout << "Foo" << endl; }
};

template <typename T>
struct Baz {
    T t;
    Baz() { cout << "Baz" << endl; }
};

template <typename T>
struct Bar {
    T t;
    Bar() { cout << "Bar" << endl; }
};



template <template <typename > class T,class Y>
struct Bar<T<Y>> 
{
    T<Y> data;
    Bar() : data() { cout << "Bar Specialization" << endl; }
};

int main()
{
    Bar<Foo<>> a; //matches the specialization with T = template<typename> Foo and Y=int

    Bar<Baz<float>> b; //matches the specialization with T = template<typename> Baz and Y=float

    Bar<int> c; //matches the primary template with T=int

    return 0;
}

Demo

0 голосов
/ 14 октября 2018

typename X является только частью сигнатуры параметров шаблона шаблона, вы можете просто написать template<template<typename> class T> (без имени для параметра T).

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

template<typename X>
struct GenericThing
{
    X data;
};

template<template<typename> class T, typename E>
struct Bar
{
    T<E> sub; // instantiate T with E
    Bar() : sub() { cout << "Bar" << endl; }
};

int main()
{
    Bar<GenericThing, int> intbar;
    Bar<GenericThing, float> floatbar;
    return 0;
}
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...