Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Uniform initialization on a vector of vectors of integers

C++11

The program initializes a vector, named myVec, of int vectors, and then uses a loop to print out each inner vector's elements. But I got unexpected results when trying to see what happens when I use extra curly braces. The following is also on this LiveWorkSpace for easy toggling between compilers. g++ 4.8.0 only compiles up to myVec[5]. clang++ 3.2 compiles everything:

#include <iostream>
#include <vector>

int main()
{
    std::vector<std::vector<int>> myVec =
    {
        /* myVec[0] */ {1, 2},
        /* myVec[1] */ {},
        /* myVec[2] */ {{}},
        /* myVec[3] */ { {}, {} },
        /* myVec[4] */ { {}, {}, {} },
        /* myVec[5] */ {{{}}}

        /* myVec[6] */  // , { {{}}, {{}} }       // g++ 4.8.0 COMPILER ERROR
        /* myVec[7] */  // , {{{{}}}}             // g++ 4.8.0 COMPILER ERROR
        /* myVec[8] */  // , { {{{}}}, {{{}}} }   // g++ 4.8.0 COMPILER ERROR
    };

    // loop for printing
    for (unsigned int i = 0; i < myVec.size(); ++i)
    {
        std::cout << "myVec[" << i << "]: ";
        for (unsigned int j = 0; j < myVec.at(i).size(); ++j)
        {
            std::cout << myVec.at(i).at(j) << ", ";
        }
        std::cout << std::endl;
    }
    return 0;
}

Actual g++ 4.8.0 output:

myVec[0]: 1, 2,
myVec[1]:
myVec[2]: 0,
myVec[3]: 0, 0,
myVec[4]: 0, 0, 0,
myVec[5]: 0,

Analysis:

myVec[0] : {1, 2} :

Got expected output.

myVec[1] : {} :

Got expected output.

myVec[2] : {{}} :

This is a vector of the int 0. The inner brace initializes an int to 0.

myVec[3] : { {}, {} } :

The two inner braces initializes an int each to 0.

myVec[4] : { {}, {}, {} } :

The three inner braces initializes an int each to 0.

myVec[5] : {{{}}} :

I wanted to add yet another set of curly braces to myVec[2] to see how far I can go with adding braces before getting compiler errors. I don’t understand why this compiles and why its element prints as 0.

For example, int j = {} initializes j to 0. vector<vector<int>> v = { {{}} } initializes the innermost {} to int 0, making it equivalent to vector<vector<int>> v = { {0} }. Then, what is vector<vector<int>> u = { {{{}}} } and why would it compile?

The Hypothetical myVec[6] : { {{}}, {{}} } :

Following the same pattern as above, I wanted to make a vector that contains two sets of double curly braces. But this doesn’t compile, and I don’t understand why this breaks the pattern of giving me multiple zeroes.

The Hypothetical myVec[7] : {{{{}}}} :

I wanted to add yet another set of curly braces to myVec[5] to see how far I can go with adding braces before getting compiler errors. I don’t understand why this breaks the pattern and doesn't compile.

The Hypothetical myVec[8] : { {{{}}}, {{{}}} } :

I wanted to extend myVec[7] to to make a vector with two sets of triple braces. I don't understand why this doesn't compile either.

If everything up to myVec[5] compiles, why doesn't the rest?

like image 411
CodeBricks Avatar asked Mar 03 '13 05:03

CodeBricks


People also ask

What is uniform initialization?

Uniform initialization is a feature in C++ 11 that allows the usage of a consistent syntax to initialize variables and objects ranging from primitive type to aggregates. In other words, it introduces brace-initialization that uses braces ({}) to enclose initializer values.

What is the correct way to initialize vector in?

Begin Declare v of vector type. Call push_back() function to insert values into vector v. Print “Vector elements:”. for (int a : v) print all the elements of variable a.


1 Answers

Try to compile this code. it should explain your issue:

int i = {};   // initializes i to int()
int j = {{}}; // fails to compile

why {{{}}} is accepted in your code seems to be a gcc bug(needs to clarify) related how ctor is processed:

struct foo {
    foo( std::initializer_list<int> ) {}
};
void f()
{
   foo bar1( {{{}}} ); // compiles fine
   foo bar2 = {{{}}}; // compiles fine
}

Edit (thanks to Johannes Schaub) - deleting copy ctor makes first variant uncompilable:

struct foo {
    foo( std::initializer_list<int> ) {}
    foo( const foo& ) = delete;
};
void f()
{
   foo bar1( {{{}}} ); // fails to compile: use of deleted function ‘foo::foo(const foo&)’
   foo bar2 = {{{}}}; // still compiles, neither deleting move ctor, nor assignment operator does not affect that, is copy ctor of std::initializer_list involved?
}

for member function it fails:

struct foo {
    void moo( std::initializer_list<int> ) {}
};
void f()
{
   foo bar;
   bar.moo( {{{}}} ); // fails to compile
}

This code fails as well:

std::initializer_list<int> l = {{{}}}; // fails to compile

Same situation ctor vs member function for std::vector:

void f()
{
    std::vector<int> v( {{{}}} ) // compiles fine;
    v.assign( {{{}}} ); // fails to compile
};

gcc version 4.7.2 (Ubuntu/Linaro 4.7.2-2ubuntu1)

like image 52
Slava Avatar answered Sep 28 '22 12:09

Slava