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

Что такое угловые скобки для значений аргументов и для чего они используются?

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

vector<int> vecOfInts ;

Но в rapidjson есть такой код:

document.Parse<0>(json) ;

Подпись метода document.Parse:

template <unsigned parseFlags>
GenericDocument& Parse(const Ch* str) {
    RAPIDJSON_ASSERT(!(parseFlags & kParseInsituFlag));
    GenericStringStream<Encoding> s(str);
    return ParseStream<parseFlags>(s);
}

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

Что здесь делает код и почему он передает значение в угловых скобках?

Это хорошая идея? Когда?

4b9b3361

Ответ 1

Здесь есть два разных фактора.

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

template <typename T, size_t N> struct Array {
    T arr[N];
};

Мы можем использовать это как

Array<int, 137> myArray;

Мы знаем, что vector<int> и vector<double> - разные типы. Но теперь мы должны также указать, что Array<int,137> и Array<int,136> являются разными типами.

Во-вторых, при использовании шаблонов компилятор должен уметь вычислять значение для всех аргументов шаблона. Когда вы используете классы шаблонов, вот почему вы обычно указываете все аргументы шаблона. Например, вы не говорите vector x, но вместо этого говорите что-то вроде vector<double> x. При использовании функций шаблона большую часть времени компилятор может определить аргументы. Например, чтобы использовать std::sort, вы просто скажете что-то вроде

std::sort(v.begin(), v.end());

Однако вы также можете написать

std::sort<vector<int>::iterator>(v.begin(), v.end());

чтобы быть более явным. Но иногда у вас есть функция шаблона, для которой не все аргументы могут быть выяснены. В вашем примере у нас есть следующее:

template <unsigned parseFlags>
GenericDocument& Parse(const Ch* str) {
    RAPIDJSON_ASSERT(!(parseFlags & kParseInsituFlag));
    GenericStringStream<Encoding> s(str);
    return ParseStream<parseFlags>(s);
}

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

Parse<0>(myString);

Здесь 0 является аргументом шаблона (разрешенным во время компиляции), а myString является фактическим аргументом (разрешенным во время выполнения).

На самом деле у вас могут быть методы, которые сочетают двоичный тип вывода и немного явных параметров типа. Например, в Boost существует функция lexical_cast, которая может выполнять преобразования в типы строк и из них. Подпись функции для преобразования из нестрокового типа в тип строки:

template <typename Target, typename Source>
    Target lexical_cast(const Source& arg);

Здесь, если вы вызываете lexical_cast, компилятор может определить, что такое Source, но он не может выводить Target без каких-либо подсказок. Чтобы использовать lexical_cast, вы должны написать что-то вроде

std::string myString = boost::lexical_cast<std::string>(toConvertToString);

В более общем плане, компилятор говорит, что вам нужно указать некоторое количество аргументов шаблона (необязательно 0), и он попытается вывести остальное. Если это возможно, отлично! Если нет, это ошибка времени компиляции. Используя это, если хотите, вы могли бы написать такую ​​функцию, как

template <int IntArgument, typename TypeArgment>
    void DoSomething(const TypeArgument& t) {
       /* ... */
}

Чтобы вызвать эту функцию, вам нужно вызвать ее так:

DoSomething<intArg>(otherArg);

Здесь это работает, потому что вы должны явно указать компилятору, что IntArgument, но тогда компилятор может вывести TypeArgument из типа аргумента в DoSomething.

Надеюсь, это поможет!