Можно ли использовать общий тип шаблона на C ++? [Дубликат]

Короче говоря, объекты Java обладают некоторыми очень своеобразными свойствами.

В общем, Java имеет примитивные типы (int, bool, char, double и т. д.), которые передаются непосредственно по значению. Тогда у Java есть объекты (все, что происходит от java.lang.Object). Объекты на самом деле всегда обрабатываются посредством ссылки (ссылка является указателем, который вы не можете коснуться). Это означает, что по сути объекты передаются по ссылке, так как ссылки обычно не интересны. Тем не менее, это означает, что вы не можете изменить, на какой объект указывается, поскольку сама ссылка передается по значению.

Звучит ли это странно и запутанно? Рассмотрим, как C реализует передачу по ссылке и передает значение. В C по умолчанию принято передать значение. void foo(int x) передает значение int по значению. void foo(int *x) - это функция, которая не хочет int a, а указатель на int: foo(&a). Можно было бы использовать это с оператором & для передачи адреса переменной.

Возьмите это на C ++, и у нас есть ссылки. Ссылки в основном (в этом контексте) синтаксического сахара, которые скрывают указательную часть уравнения: void foo(int &x) вызывается foo(a), где сам компилятор знает, что это ссылка и адрес без ссылки a должен быть принят. В Java все переменные, относящиеся к объектам, фактически относятся к ссылочному типу, фактически вызывая вызов по ссылке для большинства целей и целей без мелкозернистого управления (и сложности), предоставляемого, например, C ++.

910
задан MSalters 1 June 2016 в 12:28
поделиться

5 ответов

939
ответ дан Alan 28 August 2018 в 10:45
поделиться

Этот ответ должен быть довольно коротким и сладким, чтобы ответить (часть) озаглавленного вопроса. Если вы хотите получить более подробный ответ, объясняющий, почему вы должны их там поместить, пожалуйста, перейдите здесь .


Общее правило для размещения typename в основном, когда вы используете параметр шаблона, и хотите получить доступ к вложенному typedef или с использованием псевдонима, например:

template<typename T>
struct test {
    using type = T; // no typename required
    using underlying_type = typename T::type // typename required
};

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

template<typename T>
struct test {
    // typename required
    using type = typename std::conditional<true, const T&, T&&>::type;
    // no typename required
    using integer = std::conditional<true, int, float>::type;
};

Общие правила добавления определителя template в основном аналогичны, за исключением они обычно включают шаблонные функции-члены (статические или другие) структуры / класса, которые сами шаблоны, например:

Учитывая эту структуру и функцию:

template<typename T>
struct test {
    template<typename U>
    void get() const {
        std::cout << "get\n";
    }
};

template<typename T>
void func(const test<T>& t) {
    t.get<int>(); // error
}

Попытка доступа t.get<int>() изнутри функции приведет к ошибке:

main.cpp:13:11: error: expected primary-expression before 'int'
     t.get<int>();
           ^
main.cpp:13:11: error: expected ';' before 'int'

Таким образом, в этом контексте вам понадобится ключевое слово template заранее и вызвать его так:

t.template get<int>()

Таким образом, компилятор будет анализировать это правильно, а не t.get < int.

120
ответ дан Community 28 August 2018 в 10:45
поделиться
typedef typename Tail::inUnion<U> dummy;

Однако я не уверен, что реализация inUnion верна. Если я правильно понимаю, этот класс не должен быть создан, поэтому вкладка «fail» никогда не будет автоматически терпеть неудачу. Возможно, было бы лучше указать, находится ли тип в объединении или нет с простым булевым значением.

template <typename T, typename TypeList> struct Contains;

template <typename T, typename Head, typename Tail>
struct Contains<T, UnionNode<Head, Tail> >
{
    enum { result = Contains<T, Tail>::result };
};

template <typename T, typename Tail>
struct Contains<T, UnionNode<T, Tail> >
{
    enum { result = true };
};

template <typename T>
struct Contains<T, void>
{
    enum { result = false };
};

PS: Посмотрите на Boost :: Variant

PS2: посмотрите на typelists , особенно в книге Андрея Александреску: Modern C ++ Design

18
ответ дан Luc Touraille 28 August 2018 в 10:45
поделиться

Я помещаю превосходный ответ JLBorges на аналогичный вопрос дословно из cplusplus.com, так как это наиболее краткое объяснение, которое я прочитал по этому вопросу.

] В шаблоне, который мы пишем, есть два типа имен, которые можно использовать - зависимые имена и не зависимые имена. Зависимое имя - это имя, которое зависит от параметра шаблона; неизменяемое имя имеет то же значение, независимо от параметров шаблона.

Например:

template< typename T > void foo( T& x, std::string str, int count )
{
    // these names are looked up during the second phase
    // when foo is instantiated and the type T is known
    x.size(); // dependant name (non-type)
    T::instance_count ; // dependant name (non-type)
    typename T::iterator i ; // dependant name (type)

    // during the first phase, 
    // T::instance_count is treated as a non-type (this is the default)
    // the typename keyword specifies that T::iterator is to be treated as a type.

    // these names are looked up during the first phase
    std::string::size_type s ; // non-dependant name (type)
    std::string::npos ; // non-dependant name (non-type)
    str.empty() ; // non-dependant name (non-type)
    count ; // non-dependant name (non-type)
}

То, что зависит от зависимого имени, может быть чем-то другим для каждого конкретного экземпляра шаблона. Как следствие, шаблоны C ++ подвержены «двухфазному поиску имен». Когда шаблон сначала анализируется (до того, как выполняется какое-либо создание), компилятор просматривает не зависящие имена. Когда происходит конкретное создание шаблона, параметры шаблона известны к тому времени, и компилятор ищет зависимые имена.

На первом этапе анализатор должен знать, является ли зависимое имя именем типа или имени не-типа. По умолчанию зависимым именем считается имя не-типа.

Использовать ключевое слово typename только в объявлениях шаблонов и определениях, приведенных ниже.


у вас есть квалифицированное имя, которое относится к типу и зависит от параметра шаблона.

1
ответ дан Nik-Lz 28 August 2018 в 10:45
поделиться
120
ответ дан Community 28 August 2018 в 10:45
поделиться
Другие вопросы по тегам:

Похожие вопросы: