我正在将一个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上的Live example。但是,g ++ - 5.1和当前的trunk发布错误:
朋友模板的声明中不允许使用'constexpr' 专业化
问题:这是一个已知的g ++错误,还是Clang不符合最新标准?
注意:以上仅使用C ++ 11样式constexpr
功能,因为operator==
内没有进行任何修改,因此模板之间似乎有一些奇怪的干扰,朋友和constexpr。
更新:在Bugzilla上以bug 65977归档。
答案 0 :(得分:34)
GCC在这里错了。
所有引用都是针对N4431,最新的C ++ WD。 p>
[tl; dr:内联的函数之间存在差异(或更准确地说,是内联函数,如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
说明符,那么该声明应该是一个定义,或者该函数先前已经内联声明。
这样做的目的是允许在大多数情况下忽略好友声明 - 不允许他们添加&#34;新信息&#34;对于友好实体,除非在他们定义朋友功能的特殊情况下。 (这反过来允许实现延迟解析类定义,直到它需要&#34;。)因此我们也看到,在(8.3.6)/ 4中:
如果朋友声明指定了默认参数表达式,则该声明应该是一个定义,并且应该是翻译单元中函数或函数模板的唯一声明。
同样适用于函数模板的朋友特化的声明:如果它可以添加额外的信息,那么实现不能延迟解析类定义。
现在,请注意,此基本原理 不适用于constexpr
:如果constexpr
说明符出现在函数的任何声明中,它必须出现在每个声明,每(7.1.5)/ 1。由于没有&#34;新信息&#34;在这里,没有必要限制。