Radim Vansa
Radim Vansa

Reputation: 5888

C++0x initializer list passed by reference

I have tried to use C++0x initializer list as argument to a constructor call in this way:

Foo<float> foo("Foo 1", std::vector<const char *>({ "foo A", "foo B" }) );

with the constructor

Foo(const char *name, std::vector<const char *> &foos)

With this constructor the compiler complained:

error: no matching function for call to Foo<float>::Foo(
    const char [5], std::vector<const char *, std::allocator<const char *> >)
note: candidates are: Foo<T>::Foo(const char *, std::vector<const char *,
    std::allocator<const char *> >&) [with T = float]

However, when I've changed the constructor to

Foo(const char *name, std::vector<const char *> foos)

Everything worked as expected. Why does the first constructor not work? I thought the vector could be constructed in the place of constructor call and passed down by reference, but obviously there's some problem. Could anybody explain that?

Thanks

Btw. I am using g++ version 4.4.5

EDIT: Thanks to the correct answers below, I have found also why I can't do that.

Upvotes: 9

Views: 3145

Answers (6)

Kerrek SB
Kerrek SB

Reputation: 477040

You already have your answer, but since you have "initializer list" in the title, you may want to consider writing a (C++0x) initializer-list constructor, e.g. like so:

struct Foo {
    Foo(const char* name, std::initalizer_list<const char*> il)
      : name(name), buf(il)
    { }
private:
    const char * const name;
    std::vector<const char *> buf;
};

Then you're no longer an aggregate, but you can construct it like so:

Foo x("Name", { "ab", "cd", "ef" });

You even pass il as const-reference if you prefer.

Upvotes: 0

pure cuteness
pure cuteness

Reputation: 1645

std::vector<const char *> &foos is lvalue reference. You are trying to pass rvalue, this is wrong. You can use either rvalue reference std::vector<const char *> &&foos or const reference const std::vector<const char *> &foos

Upvotes: 1

Lightness Races in Orbit
Lightness Races in Orbit

Reputation: 385144

You cannot bind a temporary to a T&.

You can bind a temporary to T const&:

Foo(const char* name, std::vector<const char*> const& foos)

But I'd question the sanity of a vector of char pointers. What's wrong with std::string?

Upvotes: 10

Puppy
Puppy

Reputation: 146930

You cannot bind an rvalue std::vector to a non-const lvalue reference. You must take a const lvalue reference or an rvalue reference.

Upvotes: 0

Sarfaraz Nawaz
Sarfaraz Nawaz

Reputation: 361422

Temporary cannot be bound to non-const reference, so do this:

Foo(const char *name, const std::vector<const char *> &foos)
                    //^^^^ note this

Upvotes: 4

tokage
tokage

Reputation: 186

The initializer list is a red hering, I think. You are trying to bind a temporary to a non-const reference, which is illegal. Try using a const reference.

Foo(const char *name, std::vector<const char *> const& foos)

Upvotes: 2

Related Questions