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
.