doomista
doomista

Reputation: 531

How to write proper std::initializer_list constructor

Consider following code:

#include <iostream>
#include <vector>

struct C {
    std::vector<int> a;
    std::string b;
    bool c;
};

void printC(const C &c) {
    // ...
}

int main() {
    printC({
        { 1, 2, 3 },
        "ehlo",
        false
    });
}

This works, because compiler can generate proper constructor for me. But if I change struct C to this:

struct C {
    std::vector<int> a;
    std::string b;
    bool c;

    C() {
        c = false;
    }
};

The printC call stops working because compiler stops generating appropriate constructor. I've tried to write myself a constructor using std::initializer_list but failed.

So the question is - How to write constructor that will make the above code compile and work again?

Upvotes: 6

Views: 642

Answers (3)

I've tried to write myself a constructor using std::initializer_list but failed.

You don't need one. You just need a c'tor taking a vector, string and boolean:

C(std::vector<int> a, std::string b, bool c) 
  : a(std::move(a))
  , b(std::move(b))
  , c(c) {
}

Your code should now be well-formed again. Though now it incurs two move operations, while the original aggregate version could have initialized the elements of your object directly. It's something worth considering.

Upvotes: 6

T.C.
T.C.

Reputation: 137394

Worth noting that in C++14 and later you can just use a default member initializer:

struct C {
    std::vector<int> a;
    std::string b;
    bool c = false;
};

Also, aggregate initialization generates no constructors. It bypasses them entirely.

Upvotes: 5

lubgr
lubgr

Reputation: 38325

You can pass an instance of a std::initializer_list<int> like this:

#include <initializer_list>

struct C {
    /* Data members... */

    C(std::initializer_list<int> vecData, std::string str, bool flag) :
        a{vecData}, b{std::move(str)}, c{flag} {}
};

Upvotes: 2

Related Questions