Home > Software engineering >  Was a new constructor added to std::string in c 23 that accepts std::array<char, N>?
Was a new constructor added to std::string in c 23 that accepts std::array<char, N>?

Time:09-29

Recently a bug was discovered in our code where we were accidentally converting a std::array<char, N> to std::string. The buggy code doesn't compile in c 20 mode but compiles and //mostly// works in c 23 mode except for some edge cases with null termination. I'm using gcc 11.1.

#include <iostream>
#include <string>
#include <array>

int main()
{
    std::array<char, 3> x = {'a', 'b', '\0'};
    std::string s(x);
    std::cout << "'" << s << "'" << " has length " << s.size() << std::endl;
    //outputs "'ab' has length 3"
}

I suspect this may be related to P1989R2 - Range constructor for std::basic_string_view but I don't know what to make of it.

Is it a bug or just a weird behavior or what?

CodePudding user response:

Yes, it is related to P1989.

One of std::string's constructors is:

template< class StringViewLike >
explicit constexpr basic_string( const StringViewLike& t,
                                 const Allocator& alloc = Allocator() );

which is constrained on StringViewLike being convertible to std::string_view.

P1989 added this constructor to std::string_view:

template <class R> requires /* ... */
constexpr string_view(R&&);

The constraints there require R to be a contiguous_range with appropriate value type and a few other things. Importantly, std::array<char, N> meets those requirements, and this constructor is not explicit.

As a result, you can now construct a std::string from a std::array<char, N>.

This led to P2499 (string_view range constructor should be explicit), which suggested what the title says, and P2516 (string_view is implicitly convertible from what?), which suggested removing the constructor entirely. In the end, the decision was to make the constructor explicit rather than removing it entirely (or keeping it implicit):

template< class R >
explicit constexpr basic_string_view( R&& r );

Because the string constructor from StringViewLike is constrained on convertible to (which requires implicit construction), this means std::string is no longer constructible from std::array<char, N> (or std::vector<char> or ... ).

  • Related