宣布constexpr专业化为朋友

时间:2015-08-24 03:47:17

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

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

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

1 个答案:

答案 0 :(得分:6)

int main() { constexpr auto a  = f<void>(); }

这将功能模板f专门化为函数f<void>();在f的特化期间,编译器还尝试实例化A<void>friend f<void>()反过来声明专门化constexpr

这两个声明必须匹配constexpr

[dcl.constexpr] / 1

  

[...]如果函数或函数模板的任何声明都有constexpr说明符,那么它的所有声明都应包含constexpr说明符。 [注意:显式特化可能与constexpr说明符的模板声明不同。 - 结束记录]

如果你在friend声明中省略constexpr而不是删除看似非constexpr函数的内容,那么Clang可能会错误地输出错误,但至少它接受了正确的语法。

Gcc不应该允许该版本丢失constexpr,并且由于bug而提供constexpr时会出错。这已经在主干中得到修复,我现在可以确认它是有效的,但是当var async = require('async'), mongoose = require('mongoose'), Schema = mongoose.Schema; require('mongoose-middleware').initialize(mongoose); mongoose.connect('mongodb://localhost/test'); var testSchema = new Schema({ a: Number, b: Number, c: Number }); var Test = mongoose.model( 'Test', testSchema ); async.series( [ function(callback) { Test.remove({},callback); }, function(callback) { async.each( [ { a: 1, b: 2, c: 3 }, { a: 2, b: 1, c: 4 }, { a: 4, b: 3, c: 1 }, { a: 2, b: 2, c: 1 } ], function(item,callback) { Test.create(item,callback); }, callback ); }, function(callback) { Test.find().sort("a -b c").page({ start: 0, count: 3 },function(err,docs) { console.log(docs); callback(err); }); } ], function(err) { if (err) throw err; mongoose.disconnect(); } ); 丢失时它仍然没有提供错误。