c++ - Función de miembro llamada en decltype
c++11 member-functions (6)
El siguiente código:
struct A
{
int f(int);
auto g(int x) -> decltype(f(x));
};
No se compila con el error:
error: cannot call member function ''int B::f(int)'' without object
Si lo cambio a:
struct A
{
int f(int);
auto g(int x) -> decltype(this->f(x));
};
Me sale otro error:
error: invalid use of ''this'' at top level
¿Qué está mal con cualquiera de estos? Estoy usando gcc 4.6
Actualmente solo puede acceder a ''this'' y a los miembros de la clase dentro del cuerpo de la función, pero es probable que esto cambie pronto:
http://www.open-std.org/jtc1/sc22/wg21/docs/cwg_defects.html#1207
Aquí están las palabras mágicas:
struct A
{
int f(int);
auto g(int x) -> decltype((((A*)0) ->* &A::f)(x)) ;
};
Editar , veo por la respuesta de Mikael Persson, que así es como se hace en alza.
Después de algunas pruebas, ni decltype(declval<A>().f(x))
ni decltype(((A*)0)->f(x))
funcionarán.
Sin embargo, parece que usar boost :: bind funcionará (y es la versión "debajo del capó"):
struct A
{
int f(int);
auto g(int x) -> decltype(boost::bind(&A::f,0,x)());
auto h(int x) -> decltype((((A*)0)->*(&A::f))(x)); //similarly (what Boost.Bind does under-the-hood.
};
Por supuesto, esto no es bonito. Supongo que puedes ver cómo boost :: bind lo hace para encontrar una solución mejor.
EDITAR
Como MSN sugirió, también puedes hacer tu propia plantilla de función para resolver esto:
template< typename R, typename C, typename... Args > R member_func(R (C::*)(Args...));
struct A
{
int f(int);
auto g(int x) -> decltype(member_func(&A::f));
};
Me parece que eso no funciona porque el decltype está fuera del método y A en ese momento es un tipo incompleto (por lo que ni siquiera puedes hacer A().f(x)
).
Pero realmente no deberías necesitar eso. Fuera de la declaración de A, esto funcionará como se esperaba, en A debe conocer el tipo de retorno de la función que declaró unas líneas arriba. O simplemente podrías escribir:
struct A {
typedef int ret_type;
ret_type f(int x);
ret_type g(int x);
};
Esto incluso funciona con c ++ 03.
result_of y decltype en combinación pueden dar el tipo de retorno para una función miembro
#include <type_traits>
using namespace std;
struct A
{
int f(int i) { return i; }
auto g(int x) -> std::result_of<decltype(&A::f)(A, int)>::type
{
return x;
}
};
int main() {
A a;
static_assert(std::is_same<decltype(a.f(123)),
decltype(a.g(123))>::value,
"should be identical");
return 0;
}
Comeau no le gusta el auto
como un tipo de retorno de nivel superior, pero lo siguiente se compila correctamente:
template <typename R, typename C, typename A1> R get_return_type(R (C::*)(A1));
struct A
{
int f(int);
decltype(get_return_type(&A::f)) g(int x);
};
Básicamente, debe declarar al menos un constructo adicional que obtenga el tipo que desea. Y usa decltype
directamente.
EDITAR: Por cierto, esto también funciona bien para bucear en el tipo de retorno de una función miembro:
template <typename R, typename C, typename A1> R get_return_type(R (C::*)(A1));
struct B { int f(int); };
struct A
{
int f(int);
B h(int);
decltype(get_return_type(&A::f)) g(int x);
decltype(get_return_type(&A::h).f(0)) k(int x);
};
int main()
{
return A().k(0);
}
Por supuesto, no tiene la misma comodidad de auto f()-> ...
, pero al menos compila.