Разрешение перегрузки с ref-определителями

При работе с перегрузками функций с квалификацией ref я получаю разные результаты GCC (4.8.1) а также Лязг (2,9 и багажник). Рассмотрим следующий код:

#include <iostream>
#include <utility>

struct foo
{
int& bar() &
{
std::cout << "non-const lvalue" << std::endl;
return _bar;
}
//~ int&& bar() &&
//~ {
//~     std::cout << "non-const rvalue" << std::endl;
//~     return std::move(_bar);
//~ }
int const& bar() const &
{
std::cout << "const lvalue" << std::endl;
return _bar;
}
int const&& bar() const &&
{
std::cout << "const rvalue" << std::endl;
return std::move(_bar);
}

int _bar;
};

int main(int argc, char** argv)
{
foo().bar();
}

лязг компилирует и выводит "const rvalue", в то время как НКУ считает, что это неоднозначный вызов с двумя константно квалифицированными функциями, обе из которых являются наиболее подходящими кандидатами. Если я предоставлю все 4 перегрузки, то оба компилятора выведут "non-const rvalue",

Я хотел бы знать, какой компилятор —если есть … делает правильные вещи, и каковы соответствующие стандартные пьесы в игре.

Замечания: Причина, по которой это на самом деле имеет значение, состоит в том, что реальный код объявляет обе функции с константой constexpr, Конечно, нет выхода на std::cout а также static_cast используется вместо std::moveтак, чтобы они действовали constexpr определения. И так как в C ++ 11 constexpr все еще подразумевает constперегрузка, закомментированная в примере кода, не может быть предоставлена, так как она переопределит квалифицированную const перегрузку rvalue.

20

Решение

Во-первых, неявный параметр объекта обрабатывается как обычный параметр согласно 13.3.1.4:

Для не статических функций-членов тип неявного параметра объекта

— «lvalue ссылка на cv X» для функций, объявленных без квалификатора ref или с & реф-классификатор

— «rvalue ссылка на cv X» для функций, объявленных с && реф-классификатор

где X — класс, членом которого является функция, а cv — квалификация cv для этого члена.
объявление функции.

То, что вы спрашиваете, эквивалентно следующему:

void bar(foo&);
void bar(foo&&);
void bar(const foo&);
void bar(const foo&&);

int main()
{
bar(foo());
}

Выражение foo() это класс prvalue.

Во-вторых, неконстантная эталонная версия lvalue нежизнеспособна, так как prvalue не может с ней связываться.

Это оставляет нам три жизнеспособные функции для разрешения перегрузки.

У каждого есть один неявный параметр объекта (const foo&, foo&& или же const foo&&), поэтому мы должны оценить эти три, чтобы определить лучший матч.

Во всех трех случаях это напрямую связаны Ссылка обязательна. Это описано в описателях / инициализации (8.5.3).

Ранжирование трех возможных привязок (const foo&, foo&& а также const foo&&) описывается в 13.3.3.2.3:

Стандартная последовательность преобразования S1 — лучшая последовательность преобразования, чем стандартная последовательность преобразования S2 если

  • S1 и S2 являются ссылочными привязками, и ни одна из них не ссылается на неявный объектный параметр нестатической функции-члена, объявленной без квалификатора ref (это исключение здесь не применимо, все они имеют квалификаторы ref], и S1 связывает rvalue ссылку на rvalue [класс prvalue является rvalue] и S2 связывает ссылку lvalue.

Это означает, что оба foo&& а также const foo&& тогда лучше const foo&,

  • S1 и S2 являются привязками ссылок, и типы, на которые ссылаются ссылки, относятся к одному и тому же типу, за исключением cv-квалификаторов верхнего уровня, и типа, к которому ссылка инициализируется Ссылка S2 более cv-квалифицирована, чем тип, к которому относится ссылка, инициализированная S1.

Это означает, что foo&& лучше, чем const foo&&,

Так что Clang прав, и это ошибка в GCC. Рейтинг перегрузки для foo().bar() как следует:

struct foo
{
int&& bar() &&;             // VIABLE - BEST  (1)
int const&& bar() const &&; // VIABLE -       (2)
int const& bar() const &;   // VIABLE - WORST (3)
int& bar() &;               // NOT VIABLE

int _bar;
};

Ошибка в GCC, кажется, применяется исключительно к неявным параметрам объекта (с ref-qualifiers), для нормального параметра, похоже, правильное ранжирование, по крайней мере в 4.7.2.

28

Другие решения

Других решений пока нет …

По вопросам рекламы [email protected]