The following program attempts to construct a second string using the first string and a pointer into the middle of the first string:
#include <string>
int main() {
std::string src = "hello world";
const char* end = &src[5];
std::string dest(src.data(), end);
}
In C++14 and earlier this works. But in C++17 the call fails:
error: no matching function for call to ‘std::__cxx11::basic_string<char>::basic_string(char*, const char*&)’
std::string dest(src.data(), end);
[... full output omitted ...]
What changed to make this fail?
The construction of dest
is attempting to use the following constructor (from cppreference):
template< class InputIt >
basic_string( InputIt first, InputIt last,
const Allocator& alloc = Allocator() );
This requires that first
and last
have the exact same type. The problem is that in C++17 std::string::data
returns a non-const pointer when called on a non-const std::string
. This means the type of first
is char*
and the type of last
is const char*
. Since they differ, the template argument InputIt
cannot be deduced and the call fails.
There is no way to explicitly specify the template argument to a constructor call, but there is a solution. std::string::c_str
still returns a const char*
and the construction of dest
can use it:
std::string dest(src.c_str(), end);
Another solution would be calling data()
on a str
through a const reference:
const auto& const_src = src;
std::string dest(const_src.data(), end);
Or if you don't care about C++14 compatability you can use std::as_const
(thanks Mário Feroldi)
std::string dest(std::as_const(src).data(), end);
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With