【问题标题】:Declaring a constexpr specialization as friend将 constexpr 专业化声明为朋友
【发布时间】:2015-08-24 14:53:26
【问题描述】:

我有一个模板类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>();
}

我无法让 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>(); 

如果我在朋友声明中将其标记为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>();

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

【问题讨论】:

标签: c++ c++11 gcc clang constexpr


【解决方案1】:
int main() { constexpr auto a  = f<void>(); }

这将函数模板f特化为函数f&lt;void&gt;();在f 的特化期间,编译器还尝试实例化A&lt;void&gt;,这反过来又声明了特化friend f&lt;void&gt;()

这两个声明必须匹配constexpr

[dcl.constexpr] / 1

[...] 如果函数或函数模板的任何声明具有constexpr 说明符,则其所有声明都应包含constexpr 说明符。 [注意: 显式特化可以不同于模板声明关于constexpr 说明符。 —尾注]

当您在 friend 声明中省略 constexpr 而不是删除看似非 constexpr 的函数时,Clang 可能会更早地出错,但至少它接受正确的语法。

Gcc 不应该允许缺少constexpr 的版本,并且当您提供constexpr 时由于bug 会给出错误。此问题已在后备箱中修复,我现在可以确认它可以正常工作,尽管在缺少 constexpr 时它仍然不会提供错误。

【讨论】:

    猜你喜欢
    • 2015-07-04
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2011-03-18
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多