He estado jugando con el auto y me di cuenta de que la mayoría de los casos se puede reemplazar una variable definición con auto y, a continuación, asignar el tipo.

En el siguiente código w y x son equivalentes (por defecto inicializado int, pero no permite entrar en el potencial de copias). Es allí una manera de declarar z que tiene el mismo tipo de y?

int w{};
auto x = int{};
int y[5];
auto z = int[5];
El potencial de las copias son importantes. Usted no puede hacer esto porque usted no puede copiar los arrays.
No «por defecto inicializado int», pero «inicializados a cero int»
Al parecer, hay un problema al crear una matriz temporal y, a continuación, copiarlo, como @DavidBrown dio a entender. Incluso el uso de un typedef para un tipo de matriz de falla, debido a esto.
Implícito constructor predeterminado para un int hace cero inicializar, a diferencia de un unitialized int cuando tiene cualquier basura ya estaba en el lugar.
Excepto que no es un «constructor predeterminado implícito». Rellenar cero de int (por ejemplo) se produce por valor de inicialización y de inicialización estática, sino no inicialización predeterminada.

OriginalEl autor Graznarak | 2013-06-05

4 Comentarios

  1. 27

    TL;DR

    template<typename T, int N> using raw_array = T[N];
    
    auto &&z = raw_array<int,5>{};

    Su ejemplo de auto z = int[5]; no es legal más que auto z = int; es, simplemente porque el tipo no es un válido inicializador. Usted puede escribir: auto z = int{}; porque int{} es válido inicializador.

    Una vez que uno se da cuenta de esto, el siguiente intento sería:

    auto z = int[5]{};

    Nota que su int y[5] no tiene ningún archivo de inicialización. Si tenía entonces tendría que haber saltado directamente aquí.

    Lamentablemente esto no funciona, ya sea para ocultar la sintaxis de razones. En lugar usted debe encontrar una manera legal a nombre de la tipo de matriz en un archivo de inicialización. Por ejemplo, un typedef nombre puede ser usado en un inicializador. Un práctico reutilizables el tipo de plantilla de alias elimina el requisito oneroso de una nueva typedef para cada tipo de matriz:

    template<typename T, int N> using raw_array = T[N];
    
    auto z = raw_array<int,5>{};

    A un lado: Usted puede utilizar el tipo de plantilla de alias para solucionar el extraño «inside-out» de la sintaxis de C++, que permite a nombre de cualquier tipo de compuesto en orden, de izquierda a derecha de la moda, mediante el uso de esta propuesta.


    Desafortunadamente, debido a que el diseño de error en C y C++ que hace que la matriz-a-puntero de conversiones en la gota de un sombrero, el deducirse el tipo de la variable z es int* lugar int[5]. La variable resultante se convierte en un colgando puntero cuando la matriz temporal es destruido.

    C++14 introduce decltype(auto) que utiliza diferentes tipos de deducción de reglas, correctamente deducir un tipo de matriz:

    decltype(auto) z = raw_array<int,5>{};

    Pero ahora estamos en otro bug diseño con matrices; ellos no se comportan como adecuados objetos. Usted no puede ceder, copiar de construir, de hacer pasar por valor, etc., con las matrices. El código de arriba es como decir:

    int g[5] = {};
    int h[5] = g;

    Por todos los derechos que esto debería funcionar, pero por desgracia incorporados en matrices actuar de manera extraña en C y C++. En nuestro caso, el problema específico es que las matrices no son permitidos a tener cualquier tipo de inicializador; son estrictamente limitado a la utilización de inicializador de las listas. Una matriz temporal, inicializada por una lista de inicializador, no es en sí una lista de inicializador.


    Respuesta 1:

    En este punto Johannes Schaub hace el excelente sugerencia que podemos utilizar temporal de la extensión de la vida útil.

    auto &&z = raw_array<int,5>{};

    decltype(auto) no es necesario debido a la adición de && cambios en el deducirse tipo, por lo que Johannes Schaub la sugerencia de obras en C++11. Esto también evita la limitación de la matriz de inicializadores porque estamos inicializando una referencia en lugar de una matriz.

    Si quieres la matriz para deducir su longitud a partir de un inicializador, puede utilizar una incompleta tipo de matriz:

    template<typename T> using unsized_raw_array = T[];
    
    auto &&z = unsized_raw_array<int>{1, 2, 3};

    A pesar de que el hace lo que quiere, usted puede preferir para evitar la cruda matrices totalmente, debido al hecho de que las matrices no se comportan como los objetos de C++, y la oscuridad de su comportamiento y las técnicas utilizadas anteriormente.

    Respuesta 2:

    La std::array plantilla en C++11 actúa como un objeto apropiado, incluyendo la asignación, siendo transitable por valor, etc., y en general comportarse con cordura y consistente, donde incorporados en matrices no.

    auto z = std::array<int,5>{};

    Sin embargo, con esto te pierdas de ser capaz de tener el tipo de matriz inferir su propia longitud de un inicializador. En lugar Usted puede escribir un make_array plantilla de función que realiza la inferencia. Aquí presentamos una versión simple yo no he probado y que no hace las cosas que usted podría desear, tales como verificar que todos los argumentos son del mismo tipo, o vamos a especificar de forma explícita el tipo.

    template<typename... T>
    std::array<typename std::common_type<T...>::type, sizeof...(T)>
    make_array(T &&...t) {
        return {std::forward<T>(t)...};
    }
    
    auto z = make_array(1,2,3,4,5);
    Pero pensé que él quería ser inicializadas como y, o por defecto inicializado como int{}. Estás diciendo int[5]{} iba a funcionar?
    Sí, usted puede tener un defecto de inicializador: auto z = raw_array<int,100>{};
    Yo no puedo conseguir su primer caso de éxito para el trabajo: ideone.com/Hn7X6q
    raw_array ejemplo tiene el mismo problema: ideone.com/z0wN2l
    Lo que hacer es usar extensión de la vida con referencias, me.e auto&&.

    OriginalEl autor bames53

  2. 7

    No es el mismo, pero se puede usar array:

    auto z = std::array<int, 5>();
    De risa, hemos hecho un make_array función hace algún tiempo.

    OriginalEl autor jxh

  3. 1

    decltype trabaja con g++ 4.9.0 20130601 para esto:

    #include <iostream>
    #include <algorithm>
    
    static std::ostream& logger = std::clog;
    
    class A {
        static int _counter;
        int _id;
      public:
        A() : _id(++_counter) {
            logger << "\tA #" << _id << " c'tored\n";
        } 
    
        ~A() {
            //logger << "\tA #" << _id << " d'tor\n";
        } 
    
        inline int id() const{
            return _id;
        }
    };
    int A::_counter(0); 
    
    std::ostream& operator<<(std::ostream& os, const A& a) {
        return os << a.id();
    }
    
    int main() {
    
        auto dump = [](const A& a){ logger << a << " ";};
    
        logger << "x init\n";
        A x[5]; 
        logger << "x contains: "; std::for_each(x, x+5, dump);
    
        logger << "\ndecltype(x) y init\n";
        decltype(x) y;
        logger << "y contains: ";  std::for_each(y, y+5, dump);
        logger << std::endl;
    
        return 0;
    }

    De salida:

    x init
        A #1 c'tored
        A #2 c'tored
        A #3 c'tored
        A #4 c'tored
        A #5 c'tored
    x contains: 1 2 3 4 5 
    decltype(x) y init
        A #6 c'tored
        A #7 c'tored
        A #8 c'tored
        A #9 c'tored
        A #10 c'tored
    y contains: 6 7 8 9 10 

    OriginalEl autor Solkar

  4. 0

    No es exactamente lo mismo, y es un poco feo, pero es posible deducir el tipo de elemento de una lista de inicializador y declarar la matriz, directamente, de la siguiente manera:

    template<typename T>
    struct array_trait
    {
        using element_type = T;
        array_trait(T(&&)[]);
    };
    
    decltype(array_trait({4,5,7}))::element_type a[] = {4,5,7};
    
    std::cout << typeid(a).name() << std::endl;
    
    for (unsigned i = 0; i < 3; i++)
        std::cout << a[i] << std::endl;

    El tipo debe ser int[3] y la salida debe ser 4 5 7.

    OriginalEl autor ThomasMcLeod

Dejar respuesta

Please enter your comment!
Please enter your name here