这个不寻常的C++模板特性在Boost.Spirit中被使用,它的名称是什么?

51
下面的代码来自于Boost.Spirit x3 documentation。它使用了一种我从未见过的有趣的C++语法,几乎不可能在不知道正确术语的情况下通过搜索查询进行描述。这是类的前向声明的速记吗?在C++标准中提到了这个特性吗?
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);
}

9
为了便于您的搜索:http://en.cppreference.com/w/cpp/language/elaborated_type_specifier为您提供翻译:为了缓解您的搜索:http://en.cppreference.com/w/cpp/language/elaborated_type_specifier - chris
1
@BarrettAdair,这也声明了该类。 - chris
1
这是一个关于编程的话题,以下是翻译后的文本: 顺便提一句,对于标签来说,这个功能确实非常方便:using MyType = TaggedThing<struct UniqueTag>; 标签有助于将每个标签作为新类型,这对于将该类型别名为一行非常有用。在此处放置 struct 是我的个人偏好,它也可以是 classunionenumenum class(及其变体),就我所知。 - chris
5
有趣。我无法想象编写C++解析器是多么痛苦。谢谢大家! - Barrett Adair
1
顺便提一下,如果你想编译或调试代码,请不要使用Boost.Spirit。 - o11c
显示剩余4条评论
2个回答

41

模板的参数不一定需要在使用前先定义。实际上,使用“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;
}

如评论中所指出的那样,这区分了该模板的实例化。直接回答您的问题,指定模板实例化中的模板参数的性质被称为“精细化类型说明符”。


感谢Robert提供的详细示例。我从@chris的评论中找到了相关的C++标准章节。在C++11中,这被描述为ISO/IEC 14882:2011。 - Barrett Adair

27

这与以下内容相同:

class roman;

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

换句话说,在需要类型名称的地方写class T,首先声明T是一个类的名称,然后继续使用T作为其余表达式中使用的类型名称。
请注意,在C++中,此处声明的类型名称roman和变量名roman之间不存在冲突;这是允许的。
另一种情况是在没有模板的情况下可能会发生,例如:
void func( class bar *ptr );

如果bar未声明,则此代码正确;它会声明bar并声明函数以接受指向bar的指针。


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接