c++ c++11 gcc clang constexpr

c++ - Declarar una especialización constexpr como amigo.



c++11 gcc (1)

Tengo una clase A plantilla y una función con plantilla f que devuelve A objetos. Quiero que f<T> sea ​​amigo de A<T> y que todavía sea 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>(); }

No puedo lograr que Clang y Gcc estén de acuerdo en lo que hay aquí. Si no pongo constexpr en la declaración de amigo, gcc funciona bien pero clang no lo compilará, cometiendo errores con:

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>();

Si lo marca como constexpr en la declaración de amigo, clang compila bien pero gcc me da el error:

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ómo puedo hacer felices a todos?


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

Esto especializa la plantilla de función f como la función f<void>() ; durante la especialización de f , el compilador también intenta crear A<void> instancia de A<void> , que a su vez declara que el friend f<void>() especialización friend f<void>() .

Estas dos declaraciones deben coincidir para constexpr :

[dcl.constexpr] / 1

[...] Si alguna declaración de una función o plantilla de función tiene un especificador constexpr , todas sus declaraciones contendrán el especificador constexpr . [ Nota: una especialización explícita puede diferir de la declaración de plantilla con respecto al especificador constexpr . - nota final ]

Es probable que Clang debería estar cometiendo un error antes cuando omite constexpr en la declaración de friend lugar de eliminar lo que parece ser una función no constexpr , pero al menos acepta la sintaxis correcta.

Gcc no debería permitir que la versión falte constexpr , y da un error cuando se proporciona constexpr debido a un bug . Esto ya se ha solucionado en el troncal y puedo confirmar que funciona ahora, aunque todavía no proporciona un error cuando falta constexpr .