【问题标题】:What is the name of this unusual C++ template feature used by Boost.Spirit?Boost.Spirit 使用的这个不寻常的 C++ 模板功能的名称是什么?
【发布时间】:2017-01-07 09:51:31
【问题描述】:

下面的代码来自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);
}

【问题讨论】:

  • @BarrettAdair,这也声明了这个类。
  • FWIW,这个功能对于标签来说真的很方便:using MyType = TaggedThing&lt;struct UniqueTag&gt;; 标签对于使每个都成为新类型很有用,这对于使该类型别名一行很有用。将struct 放在我的个人偏好中 - 可能是classunionenumenum class(和变体)AFAIK。
  • 令人着迷。我无法想象编写 C++ 解析器会有多痛苦。谢谢大家!
  • 这里还有一个关于详细类型说明符的部分:stackoverflow.com/documentation/c%2b%2b/4891/keywords/18504/…

标签: c++ templates c++11 language-lawyer boost-spirit


【解决方案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;
}

正如人们在上面的 cmets 中指出的那样,这区分了模板的这种实例化。为了直接回答您的问题,在模板实例化中指定模板参数的性质称为“详细类型说明符”。

【讨论】:

  • 感谢罗伯特提供的说明性示例。我从上面@chris 的评论中找到了通往相关 C++ 标准部分的方法。在 C++11 中,这在 ISO/IEC 14882:2011 中有描述。
【解决方案2】:

同理:

class roman;

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

换句话说,在需要类型名的地方写入class T,首先声明T是一个类的名称,然后继续使用T作为用于表达式其余部分的类型名。

请注意,在 C++ 中,类型名称 roman 和在此处声明的变量名称 roman 之间没有冲突;这是允许的。


没有模板也会发生这种情况,例如:

void func( class bar *ptr );

如果 bar 未声明则正确;它声明bar,然后声明函数以获取指向bar的指针。

【讨论】:

    猜你喜欢
    • 2015-01-15
    • 2016-04-18
    • 1970-01-01
    • 2010-12-10
    • 2022-11-30
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2011-02-10
    相关资源
    最近更新 更多