【问题标题】:Qualified name of a local class本地类的限定名称
【发布时间】:2020-08-29 06:35:47
【问题描述】:

typename 声明中的关键字在其后需要一个限定的类型名称(一个在其前面带有嵌套名称分隔符的类型名称)。但是本地类或结构的限定名称是什么?示例如下:

struct A{};
namespace bb { struct B{}; }
int main()
{
    struct C{};

    typename A a; // not OK, because A is not a qualified typename
    typename ::A a; // OK, because it contains a nested name specifier
    typename B b; // not OK, because B is not a qualified typename
    typename bb::B b; // OK, because it contains a nested name specifier
    typename C c; // not OK in gcc and clang but compiles in Visual Studio
}

这是我从 clang 得到的错误:expected a qualified name after 'typename'

这是gcc报错:<source>:21:14: error: expected nested-name-specifier before 'C'

可以在typename 之后使用本地类名吗?如果是这样,那么它的限定名称是什么?该类在 clang 错误消息中报告为 main()::C,但这显然不是它的限定名称。我在 C++ 标准中找不到禁止在这种情况下使用本地类的地方。我错过了什么吗? Visual Studio 没有抱怨 typename C c; 那么它是 gcc 和 clang 中的错误吗?

附言。我知道如果我不使用模板,我可以在变量前面声明没有 typename 的变量,但我只是好奇这是语言中的错误、gcc/clang 或 Visual Studio 中的错误,还是我遗漏了一些东西。

【问题讨论】:

  • "是否可以在 typename 之后使用本地类名"。为什么?
  • @Klaus 正如我在问题中所写,我出于好奇而问这个问题
  • 寻找细节有时就像敲开C++地狱的后门:-)
  • 已知 VS 不是很符合。

标签: c++ c++11 language-lawyer


【解决方案1】:

gcc 和 clang 之类的听起来更严格和正确,而 VS 更宽松(不确定它是否属于错误)。

正如您已经正确编写的那样,typename 需要一个限定名称。即“出现在范围解析运算符:: 右侧的名称”。没有办法将:: 与本地类一起使用,这意味着没有:: 的限定名称(因此,如上面引用的定义)。这样的要求是否具有良好的逻辑,后人可能会决定,但对于价值,以下确实有效:

int main()
{
    struct C { public: struct D{}; };

    typename C::D d; // ok

    return 0;
}

同样值得一提的是,如果使用较旧的编译器,则允许在模板外部使用 typename,以 c++11 开头。

【讨论】:

    【解决方案2】:

    不错的实验。我从没想过使用typename 实例化结构。我创建了额外的代码并想知道它是否有效:

    struct C{
        int c = 1;
    };
    void foo(){
        struct C{
            int c = 0;
        };
    
        typename ::C c;
        C c_;
        std::cout << "c.c: " << c.c << std::endl; //c.c: 1
        std::cout << "c_.c: " << c_.c << std::endl; //c_.c: 0
    
        return;
    }
    
    int main()
    {
        foo();
    }
    

    我猜typename C c; 不起作用的原因是函数中定义的结构不存在链接。关键字typename 表示正在关注type。但是编译器/链接器找不到它。

    请让我知道我的假设是正确还是错误。提前致谢!

    【讨论】:

    • 但是为什么它可以在 Visual Studio 中工作呢?我在规范中也找不到任何支持您假设的内容。链接器也没有报告错误,但解析器/编译器报告了错误。
    • 我用gcc-9.3.0编译器分析了typenameclass的互换性的效果。在函数foo() 中使用class C c; 而不是typename ::C c; 有效!编译器正确选择了函数内的嵌套 C 结构。虽然关键字typename 无法编译。所以这可能不会被 C++ 标准禁止。但是,当明显跟随类型时,在实例化变量时使用前缀 typename 也是不寻常的/不必要的。因此每个编译器的处理方式可能不同。
    • 在类型前加上class 意味着使用其详细的类型说明符(en.cppreference.com/w/cpp/language/elaborated_type_specifier)而不是其标记名称(embedded.com/tag-vs-type-names)来引用类型。在这种情况下,这与typename 无关。
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2013-10-24
    相关资源
    最近更新 更多