朋友模板专业化声明中不允许使用 Constexpr?
Constexpr is not allowed in declaration of friend template specialization?
我正在将 C++14-constexpr
代码库从 Clang 移植到最新的 g++-5.1。考虑以下自制 bitset
class 的精简代码片段,该代码片段自 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() {}
Live example 在 Wandbox 上。但是,g++-5.1 和当前的 trunk 版本报错:
'constexpr' is not allowed in declaration of friend template
specialization
问题:这是已知的 g++ 错误还是 Clang 不符合最新标准?
注意:上面只使用了C++11风格的constexpr
特性,因为operator==
内部没有发生修改,所以看起来模板、朋友和 constexpr 之间的一些奇怪的干扰。
更新:在 Bugzilla 上归档为 bug 65977。
这里GCC错了
所有参考资料均指向最新的 C++ WD N4431。
[tl;dr:inline 函数(或者更准确地说,inline 函数 之间的区别在 7.1.2/2 中)并使用 inline
说明符声明。 constexpr
说明符使函数内联,但不是 inline
说明符。]
说明符在 C++ 标准的子条款 7.1 中进行了描述,并且是语法的一个元素。因此,每当标准谈到 foo
说明符出现在某处时,它意味着说明符字面上出现在源代码的(分析树)中。 inline
说明符是一个 函数说明符 ,如 7.1.2 节所述,其作用是使函数成为内联函数。 (7.1.2)/2:
A function declaration (8.3.5, 9.3, 11.3) with an inline
specifier declares an inline function.
还有另外两种方法可以不使用 inline
说明符来声明内联函数。一个在 (7.1.2)/3:
中描述
A function defined within a class definition is an inline function.
另一个在(7.1.5)/1中有描述:
constexpr functions and constexpr constructors are implicitly
inline (7.1.2).
这些都没有说行为就像 inline
说明符 一样,只是说该函数是一个内联函数。
那么为什么会有这条规则呢?
(7.1.2)/3 中有此规则的更简单形式:
If the inline
specifier is used in a friend declaration, that declaration shall be a definition or the function shall have previously been declared inline.
这样做的目的是允许在大多数情况下忽略友元声明——它们不允许将 "new information" 添加到被友化的实体中,除非它们正在定义友元函数的特殊情况. (这又允许实现延迟解析 class 定义,直到它是 "needed"。)因此我们也看到,在 (8.3.6)/4:
If a friend declaration specifies a default argument expression, that declaration shall be a definition and shall be the only declaration of the function or function template in the translation unit.
这同样适用于函数模板的友元特化的声明:如果它可以添加额外的信息,那么实现就不会延迟解析 class 定义。
现在,请注意这个基本原理 不适用于 constexpr
:如果 constexpr
说明符出现在函数的任何声明中,它必须出现在 每个 声明中,根据 (7.1.5)/1。由于这里没有"new information",所以不需要限制
我正在将 C++14-constexpr
代码库从 Clang 移植到最新的 g++-5.1。考虑以下自制 bitset
class 的精简代码片段,该代码片段自 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() {}
Live example 在 Wandbox 上。但是,g++-5.1 和当前的 trunk 版本报错:
'constexpr' is not allowed in declaration of friend template specialization
问题:这是已知的 g++ 错误还是 Clang 不符合最新标准?
注意:上面只使用了C++11风格的constexpr
特性,因为operator==
内部没有发生修改,所以看起来模板、朋友和 constexpr 之间的一些奇怪的干扰。
更新:在 Bugzilla 上归档为 bug 65977。
这里GCC错了
所有参考资料均指向最新的 C++ WD N4431。
[tl;dr:inline 函数(或者更准确地说,inline 函数 之间的区别在 7.1.2/2 中)并使用 inline
说明符声明。 constexpr
说明符使函数内联,但不是 inline
说明符。]
说明符在 C++ 标准的子条款 7.1 中进行了描述,并且是语法的一个元素。因此,每当标准谈到 foo
说明符出现在某处时,它意味着说明符字面上出现在源代码的(分析树)中。 inline
说明符是一个 函数说明符 ,如 7.1.2 节所述,其作用是使函数成为内联函数。 (7.1.2)/2:
A function declaration (8.3.5, 9.3, 11.3) with an
inline
specifier declares an inline function.
还有另外两种方法可以不使用 inline
说明符来声明内联函数。一个在 (7.1.2)/3:
A function defined within a class definition is an inline function.
另一个在(7.1.5)/1中有描述:
constexpr functions and constexpr constructors are implicitly inline (7.1.2).
这些都没有说行为就像 inline
说明符 一样,只是说该函数是一个内联函数。
那么为什么会有这条规则呢?
(7.1.2)/3 中有此规则的更简单形式:
If the
inline
specifier is used in a friend declaration, that declaration shall be a definition or the function shall have previously been declared inline.
这样做的目的是允许在大多数情况下忽略友元声明——它们不允许将 "new information" 添加到被友化的实体中,除非它们正在定义友元函数的特殊情况. (这又允许实现延迟解析 class 定义,直到它是 "needed"。)因此我们也看到,在 (8.3.6)/4:
If a friend declaration specifies a default argument expression, that declaration shall be a definition and shall be the only declaration of the function or function template in the translation unit.
这同样适用于函数模板的友元特化的声明:如果它可以添加额外的信息,那么实现就不会延迟解析 class 定义。
现在,请注意这个基本原理 不适用于 constexpr
:如果 constexpr
说明符出现在函数的任何声明中,它必须出现在 每个 声明中,根据 (7.1.5)/1。由于这里没有"new information",所以不需要限制