在友元模板专用化的声明中不允许使用Constexpr
Constexpr is not allowed in declaration of friend template specialization?
我正在将一个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。由于这里没有"新信息",因此没有必要进行限制。
- 为什么std::isnan 不是 constexpr?
- 为什么 Clang 不允许"and"作为函数名称?
- 不允许在向量中添加更多元素
- std::带有自定义缓冲区的 iostream 不允许我写入
- Visual Studio 2017 不允许我创建 C++ 专用模板
- 返回时不允许隐式转换
- 为什么 c++(g++) 不允许模板返回类型和函数名称之间有空格?
- 为什么 c++ 不允许(自动)强制转换?
- 为什么 c++11 不允许使用自动
- 为什么不允许成员函数和非成员函数之间的函数重载?
- 为什么不允许使用可变长度数组作为向量元素?
- 余数除法和不允许除以零 (c++) 时遇到问题
- C++从外部类继承的嵌套类;不允许使用不完整的类型
- 在 c++ 中三元运算符中不允许继续(关键字)吗?
- GCC constexpr 允许添加,但不允许按位添加或带地址
- 如果不允许使用constexpr,为什么sfinae在上面
- 范围和分解不允许 constexpr 的原因
- 在友元模板专用化的声明中不允许使用Constexpr
- 为什么不允许使用'constexpr'参数?
- constexpr(gcc) 错误 - 错误:在令牌之前不允许使用大括号括'{'初始值设定项