1

Apologies if I am not using C++ nomenclature correctly. I also tried searching StackOverflow and Cppreference but couldn't find information about this case.

Let's take the following piece of code.

struct Foo{
    vector<int> vec; 
    Foo(vector<int> inp) : vec(inp){};
};

struct Bar {
    Foo foo; 
    Bar(Foo inp) : foo(inp) {};   
};

int main()
{
    vector<int> vec = {1,2,3};
    Foo foo(vec);
    Bar bar1(foo);

    Bar bar2(vec);
}

So, I have Bar which has a member Foo. Foo is supposed to be initialised with a vector, while Bar takes Foo as a constructor argument. Nothing unusual here.

Surprisingly, I noticed that I am allowed to do Bar bar2(vec). Looks like there exists an implicitly defined constructor which could look like Bar(vector<int> vec) : foo(vec){} .

This is quite surprising to me. From what I know, c++ only implicitly generates default, move and copy constructs, as well as destructors. In this case, it looks like it generates a constructor which mirrors the member's argument list and passes it to the member's constructor. Is it what happens in reality? Could you please provide some more information about this behaviour?

songyuanyao
  • 169,198
  • 16
  • 310
  • 405
Patryk Kozak
  • 33
  • 1
  • 5
  • 1
    https://stackoverflow.com/questions/121162/what-does-the-explicit-keyword-mean – Alessandro Teruzzi Jun 28 '21 at 17:28
  • 2
    `Foo(vector inp)` is a non-`explicit` constructor with exactly 1 argument. This defines an implicit conversion from `vector` to `Foo`. The compiler sees that `Bar` has a constructor that wants a `Foo`, it sees you provided a `std::vector` and it sees an implicit conversion that it can use. The code works because the compiler quietly adds an intermediary steps, it does not define any new constructor for `Bar`. – François Andrieux Jun 28 '21 at 17:28
  • Okay, I haven't looked at explicit keyword while trying to explain this. Makes sense now, thank you! – Patryk Kozak Jun 28 '21 at 17:34

1 Answers1

4

Foo has a converting constructor taking a vector. In Bar bar2(vec);, vec is implicitly converted to a temporary Foo via the converting constructor, then the temporary Foo is passed to the constructor of Bar as an argument.

You can mark the Foo constructor as explicit to prohibit the implicit conversion:

struct Foo{
    vector<int> vec; 
    explicit Foo(vector<int> inp) : vec(inp){};
};

BTW: Bar::Bar(Foo) is a converting constructor, too.

Remy Lebeau
  • 555,201
  • 31
  • 458
  • 770
songyuanyao
  • 169,198
  • 16
  • 310
  • 405