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

Как называется эта необычная функция шаблона С++, используемая Boost.Spirit?

Ниже приведен код из документации Boost.Spirit x3. Он использует интересный синтаксис С++, который я никогда раньше не видел, что почти невозможно описать в поисковом запросе, не зная правильной терминологии. Является ли это сокращением для прямого объявления класса? Где эта функция упоминается в стандарте С++?

namespace parser
{
    using x3::eps;
    using x3::lit;
    using x3::_val;
    using x3::_attr;
    using ascii::char_;

    auto set_zero = [&](auto& ctx){ _val(ctx) = 0; };
    auto add1000 = [&](auto& ctx){ _val(ctx) += 1000; };
    auto add = [&](auto& ctx){ _val(ctx) += _attr(ctx); };

    // What is this? This is the very first use of the identifier `roman`.
    x3::rule<class roman, unsigned> const roman = "roman";
    //       ^^^^^^^^^^^

    auto const roman_def =
        eps                 [set_zero]
        >>
        (
            -(+lit('M')     [add1000])
            >>  -hundreds   [add]
            >>  -tens       [add]
            >>  -ones       [add]
        )
    ;

    BOOST_SPIRIT_DEFINE(roman);
}
4b9b3361

Ответ 1

Аргументы шаблона необязательно должны быть определены для использования. Использование "class roman" фактически объявляет класс roman.

Вот пример кода:

#include <iostream>
template <class T> void foo();
template<> void foo<class roman>()
{
    // allowed because roman is declared
    roman* pointer1;
    // not allowed because romania is not declared
    // romania* pointer2;
    std::cout << "Hello world!" << std::endl;
    return;
}
int main(int argc, char** argv) {
    return 0;
}

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

Ответ 2

Это то же самое, что:

class roman;

x3::rule<roman, unsigned> const roman = "roman";

Другими словами, записывая class T, где ожидается имя типа, сначала объявляет, что T - это имя класса, а затем переходит к T в качестве имени типа, используемого для остальной части выражения.

Обратите внимание, что в С++ не существует столкновения между typename roman и именем переменной roman, объявленным здесь; это разрешено.


Другой случай этого может произойти без шаблонов, например:

void func( class bar *ptr );

является правильным, если bar не объявлен; он объявляет bar, а затем объявляет функцию для указания указателя на bar.