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 especificadorconstexpr. [ Nota: una especialización explícita puede diferir de la declaración de plantilla con respecto al especificadorconstexpr. - 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 .