宣布constexpr专业化为朋友

Rya*_*ing 16 c++ gcc clang constexpr c++11

我有一个模板化的类A和一个f返回A对象的模板化函数.我想f<T>成为朋友,现在A<T>仍然是constexpr

template <typename T>
class A;

template <typename T>
constexpr A<T> f();

//f<T> is a friend of A<T>

template <typename T>
class A {
  friend /* constexpr? */ A f<T>();
  constexpr A() {}
};

template <typename T>
constexpr A<T> f() { return {}; }

int main() {
  constexpr auto a  = f<void>();
}
Run Code Online (Sandbox Code Playgroud)

我不能让clang和gcc同意这里的内容.如果我没有constexpr输入好友声明,gcc工作正常但clang不会编译它,错误的:

main.cpp:18:18: error: constexpr variable 'a' must be initialized by a constant expression
  constexpr auto a  = f<void>();
                 ^    ~~~~~~~~~
main.cpp:18:23: note: non-constexpr function 'f<void>' cannot be used in a constant expression
  constexpr auto a  = f<void>();
                      ^
main.cpp:9:12: note: declared here
  friend A f<T>(); 
Run Code Online (Sandbox Code Playgroud)

如果我constexpr在朋友声明中标记它,clang编译好,但gcc给我错误:

main.cpp:9:27: error: 'constexpr' is not allowed in declaration of friend template specialization 'A<T> f<T>()'
   friend constexpr A f<T>();
Run Code Online (Sandbox Code Playgroud)

我怎样才能让每个人都开心?

use*_*267 6

int main() { constexpr auto a  = f<void>(); }
Run Code Online (Sandbox Code Playgroud)

这专门将功能模板f作为功​​能f<void>(); 在专门化过程中f,编译器也会尝试实例化A<void>,而后者又会声明特化friend f<void>().

这两个声明必须匹配constexpr:

[dcl.constexpr]/1

[...]如果函数或函数模板的任何声明都有一个constexpr说明符,那么它的所有声明都应该包含说明constexpr符.[ 注意:显式特化可以与模板声明相对于说明constexpr符不同.- 结束说明 ]

当您constexprfriend声明中省略而不是删除看似非constexpr函数的内容时,Clang可能应该早先出错,但至少它接受正确的语法.

GCC不应该允许的版本失踪constexpr,并给出了一个错误,当你提供constexpr错误.这已经在主干中得到修复,我现在可以确认它是有效的,虽然它在constexpr丢失时仍然没有提供错误.