我正在移植 C++14-constexpr
代码库从 Clang 到最新的 g++-5.1。考虑以下本土开发的简化代码片段bitset
自 Clang 3.3 的太平岁月以来(现在已经快 2 年了!),该类就一直可以正确编译。
#include <cstddef>
template<std::size_t>
class bitset;
template<std::size_t N>
constexpr bool operator==(const bitset<N>& lhs, const bitset<N>& rhs) noexcept;
template<std::size_t N>
class bitset
{
friend constexpr bool operator== <>(const bitset<N>&, const bitset<N>&) noexcept;
//^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ <-- error from this piece
};
template<std::size_t N>
constexpr bool operator==(const bitset<N>& /* lhs */, const bitset<N>& /* rhs */) noexcept
{
return true;
}
int main() {}
实例 http://melpon.org/wandbox/permlink/EVdayJ5tzkp0Y9v7在Wandbox上。然而,g++-5.1和当前的主干版本给出了一个错误:
友元模板声明中不允许使用“constexpr”
专业化
Question:这是一个已知的 g++ bug 还是 Clang 不符合最新标准?
Note: 上面只使用了C++11风格constexpr
功能,因为内部没有进行任何修改operator==
,所以模板、朋友和 constexpr 之间似乎存在一些奇怪的干扰。
UPDATE: 归档为错误 65977 https://gcc.gnu.org/bugzilla/show_bug.cgi?id=65977关于 Bugzilla。
GCC在这里是错误的。
所有引用均针对最新的 C++ WD N4431。
[tl;dr:函数之间是有区别的inline(或者更准确地说,成为内联函数,如 7.1.2/2 中定义)并用inline
说明符。这constexpr
说明符使函数内联,但不是inline
说明符。]
说明符在 C++ 标准的第 7.1 条中进行了描述,并且是语法的一个元素。因此,每当标准谈到foo
说明符出现在某处,这意味着说明符确实出现在源代码(的解析树)中。这inline
说明符是一个函数说明符,如第 7.1.2 节所述,其作用是使函数成为内联函数。 (7.1.2)/2:
带有一个函数声明(8.3.5、9.3、11.3)inline
说明符声明一个内联函数.
还有另外两种方法可以声明内联函数,而不使用inline
说明符。 (7.1.2)/3 中描述了其中之一:
在类定义中定义的函数是内联函数。
另一个在(7.1.5)/1中描述:
constexpr 函数和 constexpr 构造函数是隐式的
内联(7.1.2)。
这些都没有说这种行为就像inline
说明符存在,只是该函数是内联函数。
那么为什么会有这个规则呢?
(7.1.2)/3 中有该规则的更简单形式:
If the inline
说明符用在友元声明中,该声明应是定义,或者该函数应事先已内联声明。
这样做的目的是允许在大多数情况下忽略友元声明——不允许它们向友元实体添加“新信息”,除非在定义友元函数的特殊情况下。 (这反过来又允许实现延迟解析类定义,直到“需要”为止。)因此,我们在 (8.3.6)/4 中也看到:
如果友元声明指定默认参数表达式,则该声明应是定义,并且应是翻译单元中函数或函数模板的唯一声明。
这同样适用于函数模板的友元特化的声明:如果它可以添加额外的信息,那么实现就不能延迟解析类定义。
现在,请注意这个基本原理确实not适用于constexpr
:如果constexpr
说明符出现在函数的任何声明上,它必须出现在every声明,按照 (7.1.5)/1。由于这里没有“新信息”,因此不需要限制。
本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)