Как сохранить квалификатор cv или ссылку на вывод типа возврата в c ++ 1y?

Сначала я создаю четыре структуры, каждая из которых возвращает значение, ссылку на l-значение, ссылку на const l-значение, ссылку на r-значение. И я использую их в обертке (B или же C), в методе func() из этих оберток,
Я хочу сохранить ссылки и квалификаторы резюме func() из A,

В C ++ 11 я использовал конечный тип возврата. Но с приходом нормального вывода возвращаемого типа в C ++ 14 я догадался, что могу пропустить завершающую часть, но только с autoвозвращаемый тип игнорирует квалификаторы и ссылки, как обычные auto,

Тогда мой вопрос заключается в том, как лучше всего добиться этого в C ++ 14, который ведет себя так же, как класс B ниже?
Иногда депрессивно писать завершающую часть (обычно decltype (возвращаемое выражение)), когда это тривиально.

struct A1 {
int func(){
return x;
}
int x{3};
};

struct A2 {
int& func(){
return x;
}
int x{3};
};

struct A3 {
const int& func(){
return x;
}
int x{3};
};

struct A4 {
int&& func(){
return std::move(x);
}
int x{3};
};

template <class A>
struct B{
auto func() -> decltype(std::declval<A>().func())
{
return a.func();
}

A a;
};

template <class A>
struct C{
auto func()
{
return a.func();
}

A a;
};

int main(){
std::cout << std::boolalpha;

B<A1> b1;
B<A2> b2;
B<A3> b3;
B<A4> b4;

static_assert(std::is_same<decltype(b1.func()), int>::value, "true");
static_assert(std::is_same<decltype(b2.func()), int&>::value, "true");
static_assert(std::is_same<decltype(b3.func()), const int&>::value, "true");
static_assert(std::is_same<decltype(b4.func()), int&&>::value, "true");

C<A1> c1;
C<A2> c2;
C<A3> c3;
C<A4> c4;

static_assert(std::is_same<decltype(c1.func()), int>::value, "true");
static_assert(std::is_same<decltype(c2.func()), int>::value, "true");
static_assert(std::is_same<decltype(c3.func()), int>::value, "true");
static_assert(std::is_same<decltype(c4.func()), int>::value, "true");
}

Обратите внимание, что эта программа без проблем компилируется в gcc 4.8 с опцией -std = c ++ 1y.

5

Решение

Предложения для C ++ 14 включают один (N3638, Джейсоном Меррилл), который определяет специальную декларацию для достижения этой цели, используя decltype(auto) вместо auto:

template <class A>
struct C{
decltype(auto) func()
{
return a.func();
}

A a;
};

GCC реализует это в 4.9 снимок, см. раздел C ++.

При изменении последних частей вашего кода на

static_assert(std::is_same<decltype(c1.func()), int>::value, "true");
static_assert(std::is_same<decltype(c2.func()), int&>::value, "true");
static_assert(std::is_same<decltype(c3.func()), const int&>::value, "true");
static_assert(std::is_same<decltype(c4.func()), int&&>::value, "true");

снимок GCC 4.9 компилирует его, а 4.8 — нет.

(Примечание: оба компилятора потерпят крах при внутренней ошибке компилятора, если вы используете -g вариант при компиляции. Это связано с Ошибка 56014.)


Для полноты, вот наиболее актуальный раздел из предложения:

Если заполнитель является спецификатором типа decltype (auto), объявленный тип переменной или возвращаемый тип функции должен быть только заполнителем. Тип, выведенный для переменной или возвращаемого типа, определяется, как описано в 7.1.6.2, как если бы инициализатор был операндом типа decl. [ Пример:

int i;
int&& f();
auto           x3a = i;        // decltype(x3a) is int
decltype(auto) x3d = i;        // decltype(x3d) is int
auto           x4a = (i);      // decltype(x4a) is int
decltype(auto) x4d = (i);      // decltype(x4d) is int&
auto           x5a = f();      // decltype(x5a) is int
decltype(auto) x5d = f();      // decltype(x5d) is int&&
auto           x6a = { 1, 2 }; // decltype(x6a) is std::initializer_list<int>
decltype(auto) x6d = { 1, 2 }; // error, { 1, 2 } is not an expression
auto          *x7a = &i;       // decltype(x7a) is int*
decltype(auto)*x7d = &i;       // error, declared type is not plain decltype(auto)

— конец примера]

10

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

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

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