6

I working with C++11 and have a Class containing the following Struct:

struct Settings{
    const std::string name;

    const std::string* A;
    const size_t a;
};

class X {
    static const Settings s;
    //More stuff
};

In the .cpp file I want to define it like this

X::s = {"MyName", {"one","two","three"}, 3};

But this does not work. However it does work using an intermediate variable

const std::string inter[] = {"one","two","three"};
X::s = {"MyName", inter, 3};

Is there a way to do it without the intermediate variable?

Haatschii
  • 9,021
  • 10
  • 58
  • 95
  • 3
    Your struct *does not* contain a const array. It contains a pointer to a const string. With that in mind, it should be easy to see why you need the "intermediate variable". – juanchopanza May 21 '13 at 18:29
  • @juanchopanza: Well, I want `A` to point to (the beginning of) a const Array. It could also be a pointer to a `const std::string`, but thats not what I want. But maybe I don't quite get what you are pointing at... – Haatschii May 21 '13 at 18:32
  • 1
    @Haatschii: you're confusing the fact that an array decays into a pointer with the idea that an array and a pointer are identical. In terms of the language semantics, an array is not a pointer. Likewise, an initializer list is not an array. The compiler can initialize an array with such a list, and it can decay an array into a pointer, but it doesn't know in your example to convert the list into an array and then decay that to a pointer. Hence the need for the intermediary, to get the initializer list converted to a contiguous array before assigning to the pointer. – Sean Middleditch May 21 '13 at 20:26

2 Answers2

5

A pointer cannot be initialized from a list of values. You could use std::vector instead:

#include <vector>

struct Settings{
    const std::string name;
    const std::vector<std::string> A;
//        ^^^^^^^^^^^^^^^^^^^^^^^^
    const size_t a;
};

You can then write:

class X {
    static const Settings s;
    //More stuff
};

const Settings X::s = {"MyName", {"one","two","three"}, 3};

Here is a live example.

As suggested by Praetorian in the comments, you may want to replace std::vector with std::array, if it is acceptable for you to specify the size of the container explicitly, and if the size does not need to change at run-time:

#include <array>

struct Settings{
    const std::string name;
    const std::array<std::string, 3> A;
//        ^^^^^^^^^^^^^^^^^^^^^^^^^^
    const size_t a;
};

And here is the live example.

Community
  • 1
  • 1
Andy Prowl
  • 124,023
  • 23
  • 387
  • 451
  • 1
    Could you explain why using vector makes the difference? – taocp May 21 '13 at 18:32
  • 1
    @taocp: Because a pointer cannot be initialized with a list of values. What you want is something that can be initialized from an initializer list – Andy Prowl May 21 '13 at 18:33
  • 3
    Or `std::array` if you don't need for it to be resizable. – Praetorian May 21 '13 at 18:33
  • @Praetorian: Indeed, if the user accepts to write the size explicitly – Andy Prowl May 21 '13 at 18:33
  • Thanks! I, hoped to get around using a vector but from your explanation I guess there is no way. `std::array` is no alternative since I can't specify the array size in the definition of the struct. By the way, is there any difference between a `const std::vector` and a `const std::array`, except that the size of the array must be given at the definition? (More a new question, but it just came to my mind) – Haatschii May 21 '13 at 18:58
  • @Haatschii: You cannot alter the content of a `const` array (e.g. `arr[0] = "Hello"`) ;) – Andy Prowl May 21 '13 at 19:04
  • @AndyProwl: Uh? But I could with a `const std::vector`? – Haatschii May 21 '13 at 19:15
  • @Haatschii: Woops, sorry, I misread your question. No, of course you can't modify a `const` vector, please disregard what I wrote. The difference is that `std::vector` will perform a run-time allocation that will get memory from the heap, while `std::array` is a thin, zero-overhead wrapper over a C-style array. – Andy Prowl May 21 '13 at 19:18
5

That's because you're storing a pointer to an array of strings, not the strings themselves; so you need an array of strings somewhere to point to. All you have is a brace-initialiser containing pointers to character arrays.

If you were to store the strings themselves (in a vector<string>, for example), then the first version would work.

Mike Seymour
  • 249,747
  • 28
  • 448
  • 644