Учитывая следующее:
#include <string>
class s1
{
private:
std::string storage;
public:
s1(s1 *newValue) { storage=*newValue; }
operator std::string () { return storage; }
};
class s2
{
private:
std::string storage;
public:
s2(s2 *newValue) { std::string temp=*newValue; storage=temp; }
operator std::string const () { return storage; }
};
class s3
{
private:
std::string storage;
public:
s3(s3 *newValue) { storage=*newValue; } // Compile Error here.
operator std::string const () { return storage; }
};
Первый (s1) и второй (s2) примеры компилируются нормально; третий - нет ... но s2 и s3 должны быть идентичными, за исключением передачи значения через временную переменную.
Загоняя сообщения об ошибках в код библиотеки, я думаю , что компилятор пытается выполнить привязку к конструктору перемещения на std :: string в случае s3.
Я не понимаю, почему он это делает; и почему я могу делать то же, что и с s2, но не с s3 - разве они не должны быть одинаковыми семантически?
Любое просветление, которое может дать кто угодно, будет МНОГО с благодарностью!
FWIW, IDE - Xcode версии 9.2 (9C40b); а вариант C ++ - gnu ++ 17. Кроме того, вот (слегка отредактированный) список ошибок из Xcode:
In file included from /Users/... big long path here... .cpp:9:
/Users/... big long path here... .hpp:77:31: error: no viable conversion from 's3' to 'std::__1::basic_string<char>'
s3(s3 *newValue) { storage=*newValue; }
^~~~~~~~~
In file included from /Users/... big long path here... .cpp:9:
In file included from /Users/... big long path here... .hpp:45:
/Applications/Xcode.app/Contents/Developer/Toolchains/XcodeDefault.xctoolchain/usr/include/c++/v1/string:763:5: note: candidate constructor not viable: no known conversion from 's3' to 'const std::__1::basic_string<char> &' for 1st argument
basic_string(const basic_string& __str);
^
/Applications/Xcode.app/Contents/Developer/Toolchains/XcodeDefault.xctoolchain/usr/include/c++/v1/string:768:5: note: candidate constructor not viable: no known conversion from 's3' to 'std::__1::basic_string<char> &&' for 1st argument
basic_string(basic_string&& __str)
^
/Applications/Xcode.app/Contents/Developer/Toolchains/XcodeDefault.xctoolchain/usr/include/c++/v1/string:778:31: note: candidate constructor not viable: no known conversion from 's3' to 'const value_type *' (aka 'const char *') for 1st argument
_LIBCPP_INLINE_VISIBILITY basic_string(const value_type* __s);
^
/Applications/Xcode.app/Contents/Developer/Toolchains/XcodeDefault.xctoolchain/usr/include/c++/v1/string:810:5: note: candidate constructor not viable: no known conversion from 's3' to 'initializer_list<value_type>' (aka 'initializer_list<char>') for 1st argument
basic_string(initializer_list<value_type> __il);
^
In file included from /Users/... big long path here... .cpp:9:
/Users/... big long path here... .hpp:78:4: note: candidate function
operator std::string const () { return storage; }
^
In file included from /Users/... big long path here... .cpp:9:
In file included from /Users/... big long path here... .hpp:45:
/Applications/Xcode.app/Contents/Developer/Toolchains/XcodeDefault.xctoolchain/usr/include/c++/v1/string:829:44: note: passing argument to parameter '__str' here
basic_string& operator=(basic_string&& __str)
^
1 error generated.
2 ответа
Решение проблемы CWG 1604 делает его плохо сформирован для прямой инициализации ссылки rvalue типа класса T
с инициализатором, который может быть преобразован в rvalue const T
, но неявная последовательность преобразования все еще может быть сформирована, потому что разрешение не меняется в зависимости от часть о неявной последовательности преобразования.
В результате в вашем примере s3
при ранжировании string::operator=(const string&)
и string::operator=(string&&)
во время разрешения перегрузки согласно [over.ics.rank] /3.2.3:
Стандартная последовательность преобразования S1 является лучшей последовательностью преобразования, чем стандартная последовательность преобразования S2, если
...
S1 и S2 являются привязками ссылок, и ни одна из них не относится к неявному объектному параметру нестатической функции-члена, объявленной без квалификатора ref, а S1 связывает ссылку rvalue с rvalue, а S2 связывает ссылку lvalue
...
Компилятор наконец выбирает string::operator=(string&&)
, что вызывает ошибку, когда действительно происходит инициализация его параметра.
В вашем примере с s2
семантика - это инициализация копирования, а не выбор правильного оператора присваивания, и привязка ссылок отсутствует. Так что все ок.
Спасибо, T.C. за указание на то, что это уже проектная проблема. CWG 2077 в этом обсуждении .
Я бы предположил (но это происходит только из-за того, что вы видите):
s2 (s2 * newValue) {std :: string temp = * newValue; storage = temp; }
Может быть выполнено автоматически компилятором посредством неявного приведения типов.
В то время как:
s3 (s3 * newValue) {storage = * newValue; }
Не может.
Сначала поместите (* newValue) в скобки и посмотрите, не неверно ли он интерпретирует ваши намерения в компиляторе. Вторая попытка выполнить явное приведение:
s3 (s3 * newValue) {хранилище = ((std :: string) (* newValue)); }
Если ни один из них не сработает, мне придется решить проблему с компилятором.
Похожие вопросы
Новые вопросы
c++
C ++ - это язык программирования общего назначения. Первоначально он был разработан как расширение C и имеет аналогичный синтаксис, но теперь это совершенно другой язык. Используйте этот тег для вопросов о коде (который должен быть) скомпилирован с помощью компилятора C ++. Используйте тег для конкретной версии для вопросов, связанных с конкретной версией стандарта [C ++ 11], [C ++ 14], [C ++ 17], [C ++ 20] или [C ++ 23] и т. Д. .