使用std :: array并使用"array"作为名称

Nie*_*ann 27 c++ using-directives c++11 stdarray

在我的C++ JSON库中,我最近使用GCC7进行了回归.我删除了受影响的代码,希望了解错误.

代码

考虑这个标题myclass.hpp:

#pragma once

template <typename X>
struct A
{
    struct value_t
    {
        X array;
    };

    static A array()
    {
        return A();
    }

    friend bool operator<(const A& lhs, const A& rhs) noexcept
    {
        return lhs.val.array < rhs.val.array;
    }

    value_t val = {};  
};
Run Code Online (Sandbox Code Playgroud)

如您所见,我在struct中使用名称"array"作为成员变量名称value_t,作为静态函数的名称.然后我在以下文件中包含标题:

#include <array>
using std::array; // note this!
#include "myclass.hpp"

int main()
{}
Run Code Online (Sandbox Code Playgroud)

问题

代码用GCC6和Clang5(使用-std=c++11)编译,但GCC7报告:

In file included from example.cpp:3:0:
myclass.hpp: In function 'bool operator<(const A<X>&, const A<X>&)':
myclass.hpp:19:40: error: wrong number of template arguments (1, should be 2)
         return lhs.val.array < rhs.val.array;
                                        ^~~~~
In file included from example.cpp:1:0:
/usr/local/Cellar/gcc/7.1.0/include/c++/7.1.0/array:94:12: note: provided for 'template<class _Tp, long unsigned int _Nm> struct std::array'
     struct array
            ^~~~~
make: *** [all] Error 1
Run Code Online (Sandbox Code Playgroud)

似乎解析器在lhs.val.arrayas中读取"数组" std::array并将以下内容<视为模板列表的开头.

如果我进行以下任何更改,则可以编译代码:

  • 移除using std::array;或移动它#include "myclass.hpp".
  • 更改return lhs.val.array < rhs.val.array;return (lhs.val.array) < rhs.val.array;.

另外,如果删除static A array()函数,任一编译器都会失败...

我的问题

  • 代码首先是正确的吗?我是否允许使用"数组"作为名称,即使我使用using std::array;
  • 如果代码是正确的,这是GCC7中的错误吗?

Mar*_*tek 4

我没有发现任何东西表明您发现的行为是可以的,但我发现以下内容可能会断言相反。

\n\n
\n

当成员模板专业化的名称出现在 后时。或\n -> 在后缀表达式中或在限定ID 中的嵌套名称说明符之后,并且后缀表达式的对象表达式\n 依赖于类型或限定ID 中的嵌套名称说明符id 引用依赖类型,但名称不是当前实例化 (14.6.2.1) 的成员,成员模板名称必须以关键字 template 为前缀。否则,该名称将被假定为非模板名称。

\n\n
[ Example:\nstruct X {\ntemplate<std::size_t> X* alloc();\ntemplate<std::size_t> static X* adjust();\n};\ntemplate<class T> void f(T* p) {\nT* p1 = p->alloc<200>(); // ill-formed: < means less than\nT* p2 = p->template alloc<200>(); // OK: < starts template argument list\nT::adjust<100>(); // ill-formed: < means less than\nT::template adjust<100>(); // OK: < starts template argument list\n}\n\xe2\x80\x94 end example ]\n
Run Code Online (Sandbox Code Playgroud)\n
\n\n

您可以按照已经建议的方式通过将比较元素放在括号中来解决 id 问题。它会破坏名字array<

\n\n
    return (lhs.val.array) < (rhs.val.array);\n
Run Code Online (Sandbox Code Playgroud)\n\n

让我们进一步简化您的代码,并删除所有可能掩盖正在发生的事情的内容。我将从仍然无法编译的原始代码开始。

\n\n
#include <cstddef> // needed for size_t\n//using std::array; brings following two lines into your code:\ntemplate< class T, std::size_t N >\nstruct array;\n\ntemplate <typename X>\nstruct A\n{\n    struct value_t { int array; };\n    value_t val = {};  \n    friend bool operator<(const A& lhs, const A& rhs) {\n        return (lhs.val.array < rhs.val.array);\n    }\n};\n
Run Code Online (Sandbox Code Playgroud)\n\n

现在让我们struct value_t { int array; };超越模板化定义:

\n\n
#include <cstddef> // needed for size_t\n//using std::array; brings following two lines into your code:\ntemplate< class T, std::size_t N >\nstruct array;\n\nstruct value_t { int array; };\n\ntemplate <typename X>\nstruct A\n{\n    value_t val = {};  \n    friend bool operator<(const A& lhs, const A& rhs) {\n        return (lhs.val.array < rhs.val.array);\n    }\n};\n
Run Code Online (Sandbox Code Playgroud)\n\n

因此,通过包含<array>到代码中,您将模板数组引入到代码中,如下所示。在模板外部带有 value_t 的版本中,有array<T>和 member array。这些是不同的事情,因此没有任何冲突。
\n当您将 value_t 放入模板中时,编译器开始尝试扩展来自该模板的内容。它尝试对成员数组执行此操作,但按照标准中的规定不应发生这种情况。

\n\n

无论如何,它看起来像 GCC 中的错误,因为当它出现在表达式中时,lhs.val.array只有在以关键字 template 为前缀时才应将其视为模板化lhs.val.template array<

\n\n

是的,在不同的上下文中使用相同的名称是完全正确的,除非它是保留字之一,而数组不是。但要小心这种名称的使用。我发现使用名称数组作为保存单个整数的变量至少会令人困惑。这个名字已经表明将会有不止一个。

\n