Eliminar referencia en decltype (devuelve T en lugar de T & donde T & es el decltype)
(Si eres un pro de C++11, salta al párrafo en negrita.)
Digamos que quiero escribir un método de plantilla que llama y devuelve el resultado de un objeto pasado cuyo tipo es el parámetro de plantilla:
template<ReturnType, T>
ReturnType doSomething(const T & foo) {
return foo.bar(); // EDIT: Might also be an expression introducing a temp val
}
Así que T
tiene que tener un método ReturnType T::bar() const
para ser utilizado en una llamada como esta:
struct MyClass {
...
int bar() const;
...
};
...
MyClass object;
int x = doSomething<int, MyClass>(object);
No tenemos que escribir MyClass
gracias a la deducción de tipo y la llamada se convierte en:
int x = doSomething<int>(object);
Pero omitir <int>
también resulta en un error de compilación porque el método no requiere devolver int para ser asignado a x
después (podría devolver char
por ejemplo).
En C++0x / 11 tenemos los auto
y decltype
con los que podemos deducir el tipo de retorno de un método de plantilla:
template<T>
auto doSomething(const T & foo) -> decltype(foo.bar()) {
return foo.bar(); // EDIT: Might also be an expression introducing a temp val
}
El compilador ahora descubrirá cuál es el tipo de foo.bar()
y solo lo usa como el tipo de retorno. Con nuestra clase concreta MyClass
esto será un int
y lo siguiente sería suficiente:
int x = doSomething(object);
Ahora a mi pregunta:
Si MyClass define bar()
como devolver un int&
, el tipo de retorno de doSomething(object)
también será un int&
= decltype(foo.bar())
. Esto es un problema, ya que como G++ ahora cumple que estoy devolviendo la referencia a temporal.
¿Cómo puedo arreglar esto? ¿Hay algo como remove_reference
que se pueda usar como remove_reference(decltype(foo.bar()))
?
Pensé en simplemente declarar un método helper que toma un T&
y devuelve un T
y luego definir el tipo de retorno de doSomething
como decltype(helper(foo.bar()))
. Pero tiene que haber una mejor manera, lo estoy sintiendo.
1 answers
Para eliminar una referencia:
#include <type_traits>
static_assert(std::is_same<int, std::remove_reference<int&>::type>::value, "wat");
En su caso:
template <typename T>
auto doSomething(const T& foo)
-> typename std::remove_reference<decltype(foo.bar())>::type
{
return foo.bar();
}
Solo para ser claro, tenga en cuenta que como está escrito devolver una referencia está bien:
#include <type_traits>
struct f
{
int& bar() const
{
static int i = 0;
return i;
}
};
template <typename T>
auto doSomething(const T& foo)
-> decltype(foo.bar())
{
return foo.bar();
}
int main()
{
f x;
return doSomething(x);
}
La referencia devuelta puede simplemente pasarse sin error. Su ejemplo en el comentario es donde se vuelve importante y útil:
template <typename T>
auto doSomething(const T& foo)
-> decltype(foo.bar())
{
return foo.bar() + 1; // oops
}
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2012-11-02 20:21:57