在友元模板专用化的声明中不允许使用Constexpr

Constexpr is not allowed in declaration of friend template specialization?

本文关键字:不允许 Constexpr 声明 友元 专用      更新时间:2023-10-16

我正在将一个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() {}

Wandbox上的实时示例。然而,g++-5.1和当前的干线发布给出了一个错误:

在友元模板的声明中不允许使用"constexpr"专业化

问题:这是已知的g++错误还是Clang不符合最新标准?

注意:上面只使用了C++11风格的constexpr功能,因为operator==内部没有进行任何修改,所以模板、好友和constexpr之间似乎存在一些奇怪的干扰。

更新:在Bugzilla上以错误65977的形式提交。

GCC在这里是错误的

所有参考都是针对最新的C++WD N4431。

[太长了,读不下去了:函数为内联(或者更准确地说,为inline函数,如7.1.2/2中所定义)和使用inline说明符声明之间存在差异。constexpr说明符使函数内联,但不是inline说明符。]

规范在C++标准的子条款7.1中进行了描述,并且是语法的一个元素。因此,每当标准谈到foo说明符出现在某个地方时,就意味着该说明符实际上出现在(的解析树)源代码中。inline说明符是函数说明符,如第7.1.2款所述,其作用是使函数成为内联函数。(7.1.2)/2:

带有inline说明符的函数声明(8.3.5、9.3、11.3)声明了内联函数

有另外两种方法可以在不使用inline说明符的情况下声明内联函数。一种描述见(7.1.2)/3:

在类定义中定义的函数是内联函数。

另一个如(7.1.5)/1:所述

constexpr函数和constexpr构造函数是隐式的内联(7.1.2)。

这两个都不表示行为就像存在inline说明符一样,只是表示函数是内联函数。

那么为什么会存在这个规则呢

在(7.1.2)/3:中有一个更简单的规则形式

如果在友元声明中使用inline说明符,则该声明应该是一个定义,或者该函数以前应该是内联声明的。

这样做的目的是允许在大多数情况下忽略好友声明——它们不允许向成为好友的实体添加"新信息",除非在定义好友函数的特殊情况下。(这反过来又允许实现延迟解析类定义,直到"需要"为止。)因此,我们也可以在(8.3.6)/4:中看到

如果友元声明指定了默认参数表达式,则该声明应是一个定义,并且应是转换单元中函数或函数模板的唯一声明。

同样适用于函数模板的友元专用化声明:如果它可以添加额外的信息,那么实现就不会延迟解析类定义。

现在,请注意,不适用于constexpr:如果constexpr说明符出现在函数的任何声明上,则它必须出现在每个声明上,根据(7.1.5)/1。由于这里没有"新信息",因此没有必要进行限制。