Где и почему я должен разместить шаблон & ldquo; template & rdquo; и & ldquo; typename & rdquo; ключевые слова?

Sormula поддерживает оператор SQL IN, позволяя вам предоставить объект java.util.Collection в качестве параметра. Он создает подготовленное заявление с? для каждого из элементов коллекции. См. Пример 4 (SQL в примере - комментарий, чтобы уточнить, что создано, но не используется Sormula).

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

2 ответа

Для парсинга программы C++ компилятор должен знать, являются ли определенные имена типами или нет. Следующий пример демонстрирует что:

t * f;

, Как это должно быть проанализировано? Для многих языков компилятор не должен знать значение имени, чтобы проанализировать и в основном знать, какое действие строка кода делает. В C++ вышеупомянутое однако может привести к весьма различным интерпретациям в зависимости от какой t средства. Если это будет тип, то это будет объявление указателя f. Однако, если это не будет тип, то это будет умножение. Таким образом, в Стандарте C++ говорится в абзаце (3/7):

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

, Как компилятор узнает то, к чему относится имя t::x, если t относится к шаблонному параметру типа? x мог быть статический международный элемент данных, который мог быть умножен или мог одинаково хорошо быть вложенным классом или определением типа, которое могло уступить объявлению. Если имя имеет это свойство - что это нельзя посмотреть вплоть до фактических аргументов шаблона, известны - тогда оно звонило зависимое имя (оно "зависит" от шаблонных параметров).

Вы могли бы рекомендовать просто ожидать, пока пользователь не инстанцирует шаблона:

Позволяют нам ожидать, пока пользователь не инстанцирует шаблона, и затем позже узнайте реальное значение [1 115].

Это будет работать и на самом деле позволяется Стандартом как возможный подход реализации. Эти компиляторы в основном копируют текст шаблона во внутренний буфер, и только когда инстанцирование необходимо, они анализируют шаблон и возможно обнаруживают ошибки в определении. Но вместо того, чтобы беспокоить пользователей шаблона (бедные коллеги!) с ошибками, совершенными автором шаблона, другие реализации принимают решение проверить шаблоны вначале и дать ошибки в определении как можно скорее, прежде чем инстанцирование даже произойдет.

, Таким образом, должен быть способ сказать компилятору, что определенные имена являются типами и что определенные имена не.

ключевое слово

"имени типа" ответ: Мы решаем, как компилятор должен проанализировать это. Если t::x зависимое имя, то мы должны снабдить префиксом его [1 117], чтобы сказать компилятору анализировать его определенным способом. В Стандарте говорится в (14.6/2):

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

существует много имен, для которых typename не необходимо, потому что компилятор, с применимым поиском имени в шаблонном определении, может выяснить, как проанализировать саму конструкцию - например, с [1 119], когда T шаблонный параметр типа. Но чтобы t::x * f; было объявление, оно должно быть записано как [1 122]. Если Вы опускаете ключевое слово, и имя взято, чтобы быть нетипом, но когда инстанцирование находит, что обозначает тип, обычные сообщения об ошибках испускаются компилятором. Иногда, ошибка, следовательно, дана во время определения:

// t::x is taken as non-type, but as an expression the following misses an
// operator between the two names or a semicolon separating them.
t::x f;

синтаксис позволяет typename только перед полностью определенными именами - он для этого взят, как предоставлено, который дисквалифицированные имена, как всегда известно, отсылают к типам, если они делают так.

А подобный глюк существует для имен, которые обозначают шаблоны, как намекнули вводным текстом.

"шаблонное" ключевое слово

Помнит начальную кавычку выше и как Стандарт требует специальной обработки для шаблонов также? Давайте возьмем следующий невинно выглядящий пример:

boost::function< int() > f;

Это могло бы выглядеть очевидным для читателя. Не так для компилятора. Вообразите следующее произвольное определение boost::function и f:

namespace boost { int function = 0; }
int main() { 
  int f = 0;
  boost::function< int() > f; 
}

Это - на самом деле допустимое выражение ! Это использует меньше оператор для сравнения boost::function с нулем (int()) и затем использует большее - чем оператор для сравнения получающегося bool с [1 129]. Однако как Вы могли бы хорошо знать, boost::function в реальной жизни шаблон, таким образом, компилятор знает (14.2/3):

После того, как поиск имени (3.4) находит, что имя является шаблонным именем, если это имя сопровождается < < всегда берется в качестве начала шаблонного списка аргументов и никогда как имя, сопровождаемое меньше оператор.

Теперь мы вернулись к той же проблеме как с [1 131]. Что, если мы еще не можем знать, является ли имя шаблоном при парсинге кода? Мы должны будем вставить template сразу перед шаблонным именем, как определено [1 133]. Это похоже:

t::template f<int>(); // call a function template

Шаблонные имена могут не только произойти после ::, но также и после -> или . в членском доступе класса. Необходимо вставить ключевое слово там также:

this->template f<int>(); // call a function template
<час>

Зависимости

Для людей, которые имеют толстые книги Standardese по их полке и которые хотят знать то, о чем точно я говорил, я буду говорить немного о том, как это определяется в Стандарте.

В объявлениях шаблона некоторые конструкции имеют различные значения в зависимости от того, какие аргументы шаблона Вы используете для инстанцирования шаблона: Выражения могут иметь различные типы или значения, переменные могут иметь различные типы, или вызовы функции могли бы закончить тем, что вызвали различные функции. Такие конструкции обычно говорятся [1 173], зависят от шаблонных параметров.

Стандарт определяет точно правила тем, зависит ли конструкция или нет. Это разделяет их на логически различные группы: Каждый ловит типы, другой ловит выражения. Выражения могут зависеть своим значением и/или своим типом. Таким образом, мы имеем с типичными добавленными примерами:

  • Зависимые типы (например: шаблонный параметр типа T)
  • Зависимые от значения выражения (например: шаблонный параметр нетипа N)
  • Зависимые от типа выражения (например: бросок к шаблонному параметру типа (T)0)

большинство правил интуитивно и создается рекурсивно: Например, тип, созданный как [1 140], является зависимым типом, если N зависимое от значения выражение, или T зависимый тип. Детали этого могут быть считаны в разделе (14.6.2/1) для зависимых типов, (14.6.2.2) для зависимых от типа выражений и (14.6.2.3) для зависимых от значения выражений.

Зависимые имена

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

Для предотвращения этой проблемы я обратился к простой интерпретации Стандартного текста. Из всех конструкций, которые обозначают зависимые типы или выражения, подмножество их представляет имена. Те имена являются поэтому "зависимыми именами". Имя может принять различные формы - в Стандарте говорится:

имя А является использованием идентификатора (2.11), функциональный идентификатор оператора (13.5), идентификатор функции преобразования (12.3.2) или шаблонный идентификатор (14.2), который обозначает объект или маркировку (6.6.4, 6.1)

, идентификатор является просто простой последовательностью символов / цифры, в то время как следующие два operator + и operator type форма. Последняя форма template-name <argument list>. Все это имена, и стандартным использованием в Стандарте, имя, могут также включать спецификаторы, которые говорят, какое пространство имен или классифицируют имя, должен искаться в.

зависимое выражение 1 + N значения А не является именем, но N. Подмножество всех зависимых конструкций, которые являются именами, называют зависимое имя . Имена функций, однако, могут иметь другое значение в различных инстанцированиях шаблона, но к сожалению не пойманы этим общим правилом.

Зависимые имена функций

Не, прежде всего, беспокойство этой статьи, но все еще стоящий упоминания: Имена функций являются исключением, которые обрабатываются отдельно. Имя функции идентификатора зависит не отдельно, но по зависимым выражениям аргумента типа, используемым в вызове. В примере f((T)0), f зависимое имя. В Стандарте это определяется в [1 154].

Дополнительные примечания и примеры

В достаточном количестве случаев нам нужны оба из [1 155] и template. Ваш код должен быть похожим на следующий

template <typename T, typename Tail>
struct UnionNode : public Tail {
    // ...
    template<typename U> struct inUnion {
        typedef typename Tail::template inUnion<U> dummy;
    };
    // ...
};

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

typename t::template iterator<int>::value_type v;

В некоторых случаях, ключевые слова запрещаются, как детализировано ниже

  • На названии зависимого базового класса, который Нельзя записать typename. Предполагается, что данное имя именем типа класса. Это верное для обоих имен в списке базового класса и списке инициализатора конструктора:

     template <typename T>
     struct derive_from_Has_type : /* typename */ SomeBase<T>::type 
     { };
    
  • В объявлениях использования возможное использовать template после последнего ::, и комитет по C++ заявивший , чтобы не работать над решением.

     template <typename T>
     struct derive_from_Has_type : SomeBase<T> {
        using SomeBase<T>::template type; // error
        using typename SomeBase<T>::type; // typename *is* allowed
     };
    
1081
ответ дан Alan 1 June 2016 в 22:28
поделиться
typedef typename Tail::inUnion<U> dummy;

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

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 };
};

пз: Взгляните на Повышение:: Вариант

PS2: Взгляните на списки типов , особенно в книге Andrei Alexandrescu: современный Дизайн

C++
20
ответ дан Luc Touraille 1 June 2016 в 22:28
поделиться
Другие вопросы по тегам:

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