14

What's the recommended way to convert a string to an array? I'm looking for something like:

template<class T, size_t N, class V>
std::array<T, N> to_array(const V& v)
{
    assert(v.size() == N);
    std::array<T, N> d;
    std::copy(v.begin(), v.end(), d.data());
    return d;
}

Does C++11 or Boost provide something like this? How do others do this? Seems silly having to copy/paste this function myself every time I need it in a project.

9
  • 6
    Erm, put it in a header? Commented Apr 17, 2012 at 11:54
  • I've got a map with about 1 million 20 (or 32) byte keys and I'd like to avoid the extra allocations and indirections required by std::string Commented Apr 17, 2012 at 12:03
  • std::string is as efficient, as std::vector - did you profile and saw there is a problem? Commented Apr 17, 2012 at 12:14
  • 1
    This is about std::array, not std::vector. Commented Apr 17, 2012 at 12:18
  • It just doesn't look that useful; if you know that your data is 20 or 32 bytes long at compile time, why are you passing it through a string? Commented Apr 17, 2012 at 15:58

5 Answers 5

9

Simply calling:

std::copy(v.begin(), v.end(), d.data());

is The way to convert a string to the array. I don't see any advantage of wrapping this into a dedicated "utility" function.

In addition, unless the compiler optimizes it, the performance may degrade with your function: the data will be copied second time when returning the array.

Sign up to request clarification or add additional context in comments.

1 Comment

That can't be used when you want to pass the array to a function directly.
7

That seems fine. There isn't such a thing in C++11, and I don't think there is one in Boost either. If you don't want to paste this all over the place, you can just put it in a header and #include that.

10 Comments

Copying a header is a bit better than copying the function, but still not ideal for something as basic as constructing an array.
You need this in every project? It strikes me as something that has a specific niche use. And that's exactly why you don't find it in C++11 or boost: it's not really a basic thing.
Typically, when you have a series of projects in a company, you put them in one phsical directory hierarchy with common libraries. Professionals don't copy the files from boost they want to use to every project using them; they have one copy of boost and use it from the same location across their projects. Similarly, if you have a utility library header with this function in it, you don't copy it to each project, you use the one header in a special location. This way, if you have to fix a function or update, you don't deal with divergence of code and bugfix multiple times.
That's fine for multiple projects in a company, but not for unrelated projects, not in a company.
@XTF : Why would two unrelated projects need this same piece of nearly-pointless code?
|
1

If you really only want convert string to an array, just use .c_str() (and work on char*). It isn't exactly array<> but may suit your needs.

1 Comment

No, it doesn't suit my needs, as that's a reference while I need a value.
1

That's fine, maybe with a minor modification in C++11.

template<class T, size_t N, class V>
std::array<T, N> to_array(const V& v)
{
    assert(v.size() == N);
    std::array<T, N> d;
    using std::begin; using std::end; 
    std::copy( begin(v), end(v), begin(d) ); // this is the recommended way
    return d;
}

That way, if you remove the assertion, this function would work even if v is a raw array.

4 Comments

That's C++11 specific. Might be ok in this case. Are you sure it's std::begin() and not just begin()? Your code would fail for classes that do have a free begin() in their own namespace.
Should probably be using std::begin; using std::end; std::copy(begin(v),end(v),begin(d));
@XTF that was not the version I wrote, I didnt put the namespace, because of name lookup that should work anyway. However I believe that bames53 suggestion makes it fully generic, using std one when it s a std container and specific one when it is not (if found).
Adding the extra using std::begin; using std::end; makes the to_array truly generic. If you use std::begin(v) you're preventing your container T from overriding begin(). Bottom line, you need the extra line to let Koenig resolution do what it's supposed to do!
1

It doesn't work with std::string, but if you're using a C string literal (char const *), C++20 introduces std::to_array for just this sort of thing:

std::array arr {"Hello, world!"};

https://en.cppreference.com/w/cpp/container/array/to_array

1 Comment

The expression does not work in C++23 on Apple Clang. The link offers good solution - to converting C string (a C array with size and chars) into an std::array.

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.