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

2

51

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);
}
Scamper answered 31/8, 2016 at 0:12 Comment(9)
It may be to disambiguate the class name "roman" from the variable name "roman."Hanging
Maybe, but it's interesting that the class doesn't even exist at the point of the rule template instantiation. Maybe it's something that is resolved on the second phase of name lookup?Scamper
To ease your searching: en.cppreference.com/w/cpp/language/elaborated_type_specifierMagen
@BarrettAdair, That declares the class as well.Magen
FWIW, this feature is really handy for tags: using MyType = TaggedThing<struct UniqueTag>; The tag is useful for making each one a new type, and this is useful for making that type alias one line. Putting struct there is my personal preference - it could be class, union, enum, or enum class (and variants) AFAIK.Magen
Fascinating. I cannot imagine how painful it must be to write a C++ parser. Thank you all!Scamper
There is also a section on elaborated type specifiers here: stackoverflow.com/documentation/c%2b%2b/4891/keywords/18504/…Boundless
As a side note, if you ever want to compile or debug your code, don't use Boost.Spirit.Rinna
"nearly impossible to describe in a search query without knowing the proper terminology" One of the greatest annoyances of life.Handle
M
41

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

Mohler answered 31/8, 2016 at 0:30 Comment(1)
Thank you Robert for the elucidating example. I found my way to the relevant C++ standard sections from the comment from @Magen above. In C++11, this is described in ISO/IEC 14882:2011.Scamper
L
27

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.

Lamination answered 31/8, 2016 at 1:38 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.