Если нет других перегрузок (скажем, f(T &)
или f(volatile T &&)
) шаблона функции (члена) template< typename T > f(T &&);
, то T &&
является так называемой ссылкой на пересылку, а T
либо U
, либо U &
для некоторых cv-квалифицированный тип U
. Но для cv-ref-qualifiers функций-членов такого правила нет. В struct S { void f() && { ; } };
S::f()
всегда имеет квалификатор rvalue-reference.
В универсальном коде было бы очень полезно избегать определения 4 (или даже 8, если мы также рассматриваем квалификатор volatile
) перегрузки некоторой функции-члена, в случаях, если все они в целом делают одно и то же.
Другая проблема, которая возникает при этом, - это невозможность определить эффективный cv-ref-qualifier для *this
в определенном смысле. Следующий код не позволяет определить, является ли ref-qualifier функции-члена operator ()
&&
из &
.
#include <type_traits>
#include <utility>
#include <iostream>
#include <cstdlib>
#define P \
{ \
using this_ref = decltype((*this)); \
using this_type = std::remove_reference_t< this_ref >; \
std::cout << qual() << ' ' \
<< (std::is_volatile< this_type >{} ? "volatile " : "") \
<< (std::is_const< this_type >{} ? "const " : "") \
<< (std::is_lvalue_reference< this_ref >{} ? "&" : "&&") \
<< std::endl; \
}
struct F
{
constexpr int qual() & { return 0; }
constexpr int qual() const & { return 1; }
constexpr int qual() && { return 2; }
constexpr int qual() const && { return 3; }
constexpr int qual() volatile & { return 4; }
constexpr int qual() volatile const & { return 5; }
constexpr int qual() volatile && { return 6; }
constexpr int qual() volatile const && { return 7; }
void operator () () & P
void operator () () const & P
void operator () () && P
void operator () () const && P
void operator () () volatile & P
void operator () () volatile const & P
void operator () () volatile && P
void operator () () volatile const && P
};
int
main()
{
{
F v;
F const c{};
v();
c();
std::move(v)();
std::move(c)();
}
{
volatile F v;
volatile F const c{};
v();
c();
std::move(v)();
std::move(c)();
}
return EXIT_SUCCESS;
}
Но было бы очень хорошо, если бы был синтаксис выше. Т.е. decltype((*this))
обозначают точный cv-ref-qual-qual тип *this
. На мой взгляд, введение такого синтаксиса в будущую версию стандарта C ++ не было бы серьезным изменением. Но &&
как пересылка cv-ref-qualifier (и это похоже на упущение комитета (а именно, рабочей группы основного языка)).
Другая последовательность может обозначать как функцию-член cv-ref-qualifier, так и тип cv-ref-qualifier *this
в ее теле: auto &&
, decltype(&&)
и т. Д.
Есть ли предложения по этой проблеме, подготовленные для использования в C ++ 17?
&
или&&
, вероятно, заслуживают отдельного вопроса. Например. на самом деле это не связано с прямыми ссылками (как раз наоборот), которые вы используете для сравнения того, что, как я считаю, является основным вопросом. - person Luc Danton   schedule 30.09.2015