Правила устранения неоднозначности метода C ++ со ссылками на rvalue - PullRequest
2 голосов
/ 15 сентября 2011

В следующем примере вызываются ctors # 1, # 1, # 4 и # 4 (в этом порядке).Я ожидаю, что вместо этого будут вызваны # 1, # 1, # 2, # 3 (дисконтирование RVO ).

//-----------------------------------------------------------------------------
struct A
{
    A(){}                   //  1

    A(A&&){}                //  2

    A(const A&){}           //  3

    template<typename T>
    A(T&&){}                //  4

    template<>
    A(A&&){}                //  5

    template<typename T>
    A(const T&){}           //  6
};

//-----------------------------------------------------------------------------
A wtf(){ A x; return x; }

//-----------------------------------------------------------------------------
int main( int, char*[] )
{
    A a;
    A c = wtf();
    A b(c);
}

Что происходит и почему?!

Примечание: удалите # 5 для компиляции с GCC (в любом случае это не так важно) - вышеприведенное компилируется с VS2010.Мне было бы интересно узнать, совпадают ли результаты в GCC, если кто-то может это проверить.

Ответы [ 3 ]

1 голос
/ 28 сентября 2011

Это ошибка компилятора.

Забудьте о неявных значениях для return local выражений (и, кстати, throw local выражений), это явно ошибка компилятора, потому что -

none шаблонных конструкторов должны были быть вызваны в вашем примере кода.

Ни одна шаблонная функция не может считаться конструктором копирования, оператором копирования, конструктором перемещения или оператором назначения перемещения.

Поддержка C ++ 11 неоднозначна, хотя gcc лучший , он все еще неполон и глючит.

0 голосов
/ 16 сентября 2011

return x; не вызывает конструктор перемещения, потому что x может не истечь.В общих чертах это просто lvalue, как и любой другой.return std::move( x ); обычно необходимо.( РЕДАКТИРОВАТЬ: , но см. Следующий абзац.)

Существует специальное правило, которое требует, чтобы компилятор выполнял операцию перемещения вместо копирования, если потенциальное удаление не выполняется, §12.8 /32.Я не уверен, почему ты этого не видишь.Возможно, компилятор пропустил это правило, потому что он не ожидает, что пользователь отключит elision.

Можно ожидать, что конструктор копирования A( A const & ) выполнит копию return, но шаблон A( T && ) реализует совершенныйпересылка.T && выводится на A &, что не const и, следовательно, лучше соответствует.

Будьте очень осторожны с идеальной пересылкой в ​​сочетании с конструкторами копирования.Я немного удивлен, что язык не имеет к этому особого отношения.Насколько я знаю, решение состоит в том, чтобы использовать SFINAE для отключения шаблона при таких обстоятельствах.

0 голосов
/ 16 сентября 2011

У вас слишком много конструкторов для реального класса.Этого не происходит, кроме как в тестовом коде.

Конструктор # 4 с T, равным A& и A& &&, свертывающимся до A&, будет лучше соответствовать A b(c), чем любой из2 (c не является значением) или # 3 (c не является константой).

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...