What is the name of this unusual C++ template feature used by Boost.Spirit?

The code below is from the Boost.Spirit x3 documentation. It uses an interesting C++ syntax that I've never seen before, which is nearly impossible to describe in a search query without knowing the proper terminology. Is this shorthand for the forward declaration of a class? Where is this feature mentioned in the C++ standard?

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

Solution 1:

The arguments to a template do not necessarily have to be defined to be used. The use of "class roman" actually declares the class roman.

Here is some example code:

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

As people have pointed out in the comments above, this distinguishes this instantiation of the template. And to directly answer the question you had, specifying the nature of the template argument in a template instantiation is called an 'elaborated type specifier'.

Solution 2:

It is the same as:

class roman;

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

In other words, writing class T where a typename is expected, first declares that T is the name of a class, and then proceeds with T as the typename being used for the rest of the expression.

Note that in C++ there is no clash between the typename roman and the variable name roman being declared here; that is allowed.


Another case of this can happen without templates, e.g.:

void func( class bar *ptr );

is correct if bar is undeclared; it declares bar and then declares the function to take a pointer to bar.