c++ - seguidores - Devolución del tipo de devolución para funciones de amigo en clase
hashtag populares instagram 2018 (1)
Con respecto a las otras respuestas: estamos tratando explícitamente con n3638 aquí, y cómo se incorpora en los borradores recientes de C ++ 1y.
Estoy usando 9514cc28 del repositorio github del comité , que ya incorpora algunas correcciones / cambios (menores) a n3638.
n3638 permite explícitamente:
struct A {
auto f(); // forward declaration
};
auto A::f() { return 42; }
Y, como podemos inferir de [dcl.spec.auto], donde se especifica esta característica, incluso lo siguiente será legal:
struct A {
auto f(); // forward declaration
};
A x;
auto A::f() { return 42; }
int main() { x.f(); }
(pero más sobre esto más adelante)
Esto es fundamentalmente diferente de cualquier búsqueda de nombre de tipo de retorno-final o dependiente, como auto f();
Es una declaración preliminar, similar a la struct A;
. Debe completarse más adelante, antes de que se use (antes de que se requiera el tipo de devolución).
Además, los problemas en el OP están relacionados con errores internos del compilador. La compilación reciente de Clang ++ 3.4 trunk 192325 Debug + Asserts no se compila porque falla una aserción al analizar el return L.b_ == R.b_;
línea return L.b_ == R.b_;
. No he comprobado con una versión reciente de g ++ a partir de ahora.
¿El ejemplo de OP es legal para un n3638?
Esto es un poco complicado IMO. (Siempre me refiero a 9514cc28 en esta sección.)
1. ¿Dónde está permitido usar `auto`?
[dcl.spec.auto]
6 Un programa que usa
auto
odecltype(auto)
en un contexto que no está explícitamente permitido en esta sección está mal formado.2 El tipo de marcador de posición puede aparecer con un declarador de función en decl-specifier-seq , type-specifier-seq , conversion-function-id o trailing-return-type , en cualquier contexto en el que dicho declarador sea válido.
/ 5 también define algunos contextos, pero son irrelevantes aquí.
Por lo tanto, auto func()
y auto operator@(..)
están generalmente permitidos (esto se deduce de la composición de una declaración de función como TD
, donde T
es de la forma decl-specifier-seq , y auto
es un especificador de tipo ) .
2. ¿Se permite escribir `auto func ();`, es decir, una declaración que no es una definición?
[dcl.spec.auto] / 1 dice
Los especificadores de tipo
auto
ydecltype(auto)
designan un tipo de marcador de posición que se reemplazará más adelante, ya sea por deducción de un inicializador o por especificación explícita con un tipo de retorno-rastreo .
y 2
Si el tipo de retorno declarado de la función contiene un tipo de marcador de posición, el tipo de retorno de la función se deduce de las declaraciones de
return
en el cuerpo de la función, si corresponde.
Aunque no permite explícitamente una declaración como auto f();
para una función (es decir, una declaración sin definición), se desprende de n3638 y [dcl.spec.auto] / 11 que se pretende que se permita, y no se prohíba explícitamente.
3. ¿Qué pasa con las funciones de amigo?
Hasta ahora, el ejemplo.
struct A
{
int a_;
friend auto operator==(A const& L, A const& R);
}
auto operator==(A const& L, A const& R)
{ return L.a_ == R.a_; }
debe estar bien formado. La parte interesante ahora es la definición de la función amiga dentro de la definición de A
, que es
struct A
{
int a_;
friend auto operator==(A const& L, A const& R)
{ return L.a_ == R.a_; } // allowed?
}
En mi opinión, está permitido. Para apoyar esto, citaré la búsqueda de nombre. La búsqueda de nombres dentro de la definición de funciones definidas en una declaración de función amiga sigue la búsqueda de nombres de funciones miembro según [basic.lookup.unqual] / 9. / 8 de la misma sección especifica la búsqueda no calificada para los nombres utilizados dentro de los cuerpos de la función miembro. Una de las formas en que se puede declarar que se usa un nombre es que "será un miembro de la clase X
o un miembro de una clase base de X
(10.2)". Esto permite a los ampliamente conocidos.
struct X
{
void foo() { m = 42; }
int m;
};
Observe cómo m
no se declara antes de su uso en foo
, pero es un miembro de X
De esto, llego a la conclusión de que incluso
struct X
{
auto foo() { return m; }
int m;
}
esta permitido. Esto está soportado por clang ++ 3.4 trunk 192325. La búsqueda de nombres requiere interpretar esta función solo después de que se haya completado la struct
, también considere:
struct X
{
auto foo() { return X(); }
X() = delete;
};
De manera similar, el cuerpo de las funciones de amigo definidas dentro de una clase solo puede interpretarse una vez que la clase está completa.
4. ¿Qué pasa con las plantillas?
Específicamente, ¿qué pasa con el friend auto some_function(B const& L) { return L.b_; }
friend auto some_function(B const& L) { return L.b_; }
?
Primero, el nombre de clase inyectado B
es equivalente a B<T>
, vea [temp.local] / 1. Se refiere a la instanciación actual ([temp.dep.type] / 1).
La expresión-expresión L.b_
refiere a un miembro de la instanciación actual (/ 4). También es un miembro dependiente de la instanciación actual . Esta es una adición realizada después de C ++ 11, vea DR1471 , y no sé qué pensar al respecto: [temp.dep.expr] / 5 indica esta identificación -expresión no depende del tipo, y por lo que veo [temp.dep.constexpr] no dice que sea dependiente del valor.
Si el nombre en L.b_
no fuera dependiente, la búsqueda de nombres seguiría las reglas de "búsqueda de nombres habituales" según [temp.nondep]. De lo contrario, esto será divertido (la búsqueda de nombres dependientes no está muy bien especificada), pero considerando eso
template<class T>
struct A
{
int foo() { return m; }
int m;
};
También es aceptado por la mayoría de los compiladores, creo que la versión con auto
debería ser válida.
También hay una sección sobre los amigos de las plantillas en [temp.friend], pero IMO no arroja luz sobre la búsqueda de nombres aquí.
También vea esta discusión altamente relevante en el foro isocpp .
Aquí hay un pequeño experimento con la deducción del tipo de retorno para funciones de amigo en clase (utilizando Clang 3.4 SVN y g ++ 4.8.1 con std=c++1y
en ambos casos) que no está documentado en el documento de trabajo vinculado
#include <iostream>
struct A
{
int a_;
friend auto operator==(A const& L, A const& R)
{
return L.a_ == R.a_; // a_ is of type int, so should return bool
}
};
template<class T>
struct B
{
int b_;
friend auto operator==(B const& L, B const& R)
{
return L.b_ == R.b_; // b_ is of type int, so should return bool
}
};
using BI = B<int>;
int main()
{
std::cout << (A{1} == A{2}) << "/n"; // OK for Clang, ERROR for g++
std::cout << (BI{1} == BI{2}) << "/n"; // ERROR for both Clang and g++
}
Pregunta : ¿se admite la deducción automática del tipo de retorno para las funciones de amigo en clase en C ++ 14?