Учитывая следующее:

#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.
c++
2
Britt 2 Янв 2018 в 00:44

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 в этом обсуждении .

1
xskxzr 3 Янв 2018 в 13:21

Я бы предположил (но это происходит только из-за того, что вы видите):

s2 (s2 * newValue) {std :: string temp = * newValue; storage = temp; }

Может быть выполнено автоматически компилятором посредством неявного приведения типов.

В то время как:

s3 (s3 * newValue) {storage = * newValue; }

Не может.

Сначала поместите (* newValue) в скобки и посмотрите, не неверно ли он интерпретирует ваши намерения в компиляторе. Вторая попытка выполнить явное приведение:

s3 (s3 * newValue) {хранилище = ((std :: string) (* newValue)); }

Если ни один из них не сработает, мне придется решить проблему с компилятором.

0
KVKConsultancy 2 Янв 2018 в 02:33