Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

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);
}
like image 742
Barrett Adair Avatar asked Aug 31 '16 00:08

Barrett Adair


2 Answers

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'.

like image 86
Robert Prévost Avatar answered Sep 20 '22 16:09

Robert Prévost


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.

like image 32
M.M Avatar answered Sep 20 '22 16:09

M.M