Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

string constructor taking two char* into another std::string works in c++14 but not c++17

Tags:

c++

c++17

c++14

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?

like image 949
Ryan Haining Avatar asked Jan 16 '18 19:01

Ryan Haining


1 Answers

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);
like image 129
Ryan Haining Avatar answered Sep 20 '22 21:09

Ryan Haining