Объявление специалиста 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
int main() { constexpr auto a = f<void>(); }
Это специализирует шаблон функции f
как функцию f<void>()
; во время специализации f
компилятор также пытается создать экземпляр A<void>
, который, в свою очередь, объявляет специализацию friend f<void>()
.
Эти два объявления должны соответствовать constexpr
:
[dcl.constexpr]/1
[...] Если какое-либо объявление шаблона функции или функции имеет спецификатор constexpr
, то все его объявления должны содержать спецификатор constexpr
. [Примечание. Явная специализация может отличаться от объявления шаблона в отношении спецификатора constexpr
. -end note]
Вероятно, что Clang должен быть ошибочным раньше, когда вы опускаете constexpr
в объявлении friend
вместо того, чтобы удалять то, что кажется не-t26, но по крайней мере оно принимает правильный синтаксис.
Gcc не должен допускать отсутствие версии constexpr
и дает сообщение об ошибке, если вы предоставляете constexpr
из-за bug. С тех пор это исправлено в багажнике, и я могу подтвердить, что он работает сейчас, хотя он все еще не дает ошибку, когда constexpr
отсутствует.