Подтвердить что ты не робот

Строковый конструктор с двумя char * в другой std::string работает в С++ 14, но не С++ 17

Следующая программа пытается построить вторую строку, используя первую строку, и указатель в середину первой строки:

#include <string>

int main() {
  std::string src = "hello world";
  const char* end = &src[5];
  std::string dest(src.data(), end);
}

В С++ 14 и ранее это работает. Но в С++ 17 сбой вызова:

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 ...]

Что изменилось, чтобы это не удалось?

4b9b3361

Ответ 1

Конструкция dest пытается использовать следующий конструктор (из cppreference):

template< class InputIt >
basic_string( InputIt first, InputIt last, 
              const Allocator& alloc = Allocator() );

Это требует, чтобы first и last имели тот же самый тип. Проблема заключается в том, что в С++ 17 std::string::data возвращает указатель non-const при вызове неконстантного std::string. Это означает, что тип first равен char*, а тип last - const char*. Поскольку они различаются, аргумент шаблона InputIt не может быть выведен и вызов не выполняется.

Невозможно явно указать аргумент шаблона вызову конструктора, но есть решение. std::string::c_str все еще возвращает const char*, и конструкция dest может использовать его:

std::string dest(src.c_str(), end);

Другим решением будет вызов data() в str через ссылку const:

const auto& const_src = src;
std::string dest(const_src.data(), end);

Или, если вам не нужна совместимость с С++ 14, вы можете использовать std::as_const (спасибо Mário Feroldi)

std::string dest(std::as_const(src).data(), end);