Buscar..


Observaciones

La palabra clave auto es un nombre de tipo que representa un tipo deducido automáticamente.

Ya era una palabra clave reservada en C ++ 98, heredada de C. En versiones anteriores de C ++, se podía usar para indicar explícitamente que una variable tiene una duración de almacenamiento automática:

int main()
{
  auto int i = 5; // removing auto has no effect
}

Ese viejo significado ahora se ha eliminado.

Muestra auto básica

La palabra clave auto proporciona la deducción automática del tipo de una variable.

Es especialmente conveniente cuando se trata de nombres tipográficos largos:

std::map< std::string, std::shared_ptr< Widget > > table;
// C++98
std::map< std::string, std::shared_ptr< Widget > >::iterator i = table.find( "42" );
// C++11/14/17
auto j = table.find( "42" );

con rango basado en bucles :

vector<int> v = {0, 1, 2, 3, 4, 5};
for(auto n: v)
    std::cout << n << ' ';

con lambdas :

auto f = [](){ std::cout << "lambda\n"; };
f();        

Para evitar la repetición del tipo:

auto w = std::make_shared< Widget >();

Para evitar copias sorprendentes e innecesarias:

auto myMap = std::map<int,float>();
myMap.emplace(1,3.14);

std::pair<int,float> const& firstPair2 = *myMap.begin();  // copy!
auto const& firstPair = *myMap.begin();  // no copy!

El motivo de la copia es que el tipo devuelto es en realidad std::pair<const int,float> !

Plantillas de auto y expresión

auto también puede causar problemas cuando las plantillas de expresión entran en juego:

auto mult(int c) {
    return c * std::valarray<int>{1};
}

auto v = mult(3);
std::cout << v[0]; // some value that could be, but almost certainly is not, 3.

La razón es que el operator* en valarray le proporciona un objeto proxy que se refiere al valarray como un medio de evaluación perezosa. Al usar auto , estás creando una referencia que cuelga. En lugar de mult ha devuelto un std::valarray<int> , entonces el código definitivamente se imprimiría 3.

auto, const, y referencias

La palabra clave auto por sí misma representa un tipo de valor, similar a int o char . Se puede modificar con la palabra clave const y el símbolo & para representar un tipo const o un tipo de referencia, respectivamente. Estos modificadores se pueden combinar.

En este ejemplo, s es un tipo de valor (su tipo se deducirá como std::string ), por lo que cada iteración del bucle for copia una cadena del vector en s .

std::vector<std::string> strings = { "stuff", "things", "misc" };
for(auto s : strings) {
    std::cout << s << std::endl;
}

Si el cuerpo del bucle modifica s (por ejemplo, al llamar a s.append(" and stuff") ), solo se modificará esta copia, no el miembro original de las strings .

Por otro lado, si s se declara con auto& será un tipo de referencia (se inferirá que es std::string& ), por lo que en cada iteración del bucle se le asignará una referencia a una cadena en el vector:

for(auto& s : strings) {
    std::cout << s << std::endl;
}

En el cuerpo de este bucle, las modificaciones a s afectarán directamente el elemento de las strings que hace referencia.

Finalmente, si s se declara const auto& , será un tipo de referencia const, lo que significa que en cada iteración del bucle se le asignará una referencia const a una cadena en el vector:

for(const auto& s : strings) {
    std::cout << s << std::endl;
}

Dentro del cuerpo de este bucle, s no se puede modificar (es decir, no hay métodos no const pueden ser llamados en él).

Cuando se utiliza el modo auto con el rango for bucles, generalmente es una buena práctica usar const auto& si el cuerpo del bucle no modifica la estructura que se está repitiendo, ya que esto evita copias innecesarias.

Tipo de retorno final

auto se utiliza en la sintaxis para el tipo de retorno final:

auto main() -> int {}

que es equivalente a

int main() {}

Mayormente útil combinado con decltype para usar parámetros en lugar de std::declval<T> :

template <typename T1, typename T2>
auto Add(const T1& lhs, const T2& rhs) -> decltype(lhs + rhs) { return lhs + rhs; }

Lambda genérica (C ++ 14)

C ++ 14

C ++ 14 permite usar auto en argumento lambda

auto print = [](const auto& arg) { std::cout << arg << std::endl; };

print(42);
print("hello world");

Esa lambda es mayormente equivalente a

struct lambda {
    template <typename T>
    auto operator ()(const T& arg) const {
        std::cout << arg << std::endl;
    }
};

y entonces

lambda print;

print(42);
print("hello world");

objetos de auto y proxy

A veces, el auto puede comportarse de la forma no esperada por un programador. El tipo deduce la expresión, incluso cuando la deducción de tipo no es lo correcto.

Como ejemplo, cuando se utilizan objetos proxy en el código:

std::vector<bool> flags{true, true, false};
auto flag = flags[0];
flags.push_back(true);

Aquí la flag no sería bool , pero std::vector<bool>::reference , ya que para la especialización bool del vector de plantilla el operator [] devuelve un objeto proxy con el operador de conversión operator bool definido.

Cuando flags.push_back(true) modifica el contenedor, esta pseudo-referencia podría terminar colgando, refiriéndose a un elemento que ya no existe.

También hace posible la siguiente situación:

void foo(bool b);

std::vector<bool> getFlags();

auto flag = getFlags()[5];
foo(flag);

El vector se descarta inmediatamente, por lo que la flag es una pseudo-referencia a un elemento que ha sido descartado. La llamada a foo invoca un comportamiento indefinido.

En casos como este, puede declarar una variable con auto e inicializarla mediante la conversión al tipo que desea deducir:

auto flag = static_cast<bool>(getFlags()[5]);

pero en ese punto, simplemente reemplazar el auto por bool tiene más sentido.

Otro caso donde los objetos proxy pueden causar problemas son las plantillas de expresión . En ese caso, las plantillas a veces no están diseñadas para durar más allá de la expresión completa actual por razones de eficiencia, y el uso del objeto proxy en la siguiente causa un comportamiento indefinido.



Modified text is an extract of the original Stack Overflow Documentation
Licenciado bajo CC BY-SA 3.0
No afiliado a Stack Overflow