Constexpr不允许声明朋友模板专业化吗?

时间:2015-04-25 21:51:00

标签: c++ templates c++11 g++ constexpr

我正在将一个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归档。

1 个答案:

答案 0 :(得分:34)

GCC在这里错了。

所有引用都是针对N4431,最新的C ++ WD。

[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;在这里,没有必要限制。