Что означает → после использования прототипа функции?

Что происходит в этом коде? Это сбивает с толку.

#include <utility>

struct check
{
   template <typename T>
   auto foo() -> decltype(std::declval<T>().value, void())
   {
      static_assert(T{}.value == 10, "Incorrect value");
   }
} var;

int main()
{
   struct apple
   {
      int value{10};
   };

   var.foo<apple>();
}

В частности, часть, где она имеет -> и все после этого.

Ответы

Ответ 1

Переходим пополам.

auto foo() -> decltype(std::declval<T>().value, void())

Это тип возвращаемого возврата. Это позволило использовать параметры, но здесь это не обязательно. Я бы предположил, что это написано так, чтобы быть яснее. decltype находит тип выражения внутри, но это выражение фактически не оценивается. std::declval используется для создания экземпляра передаваемого ему типа. Оператор запятой используется здесь для создания общего типа возврата void, так как оператор запятой оценивает левую сторону, отбрасывает его, оценивает правую сторону и возвращает это.

Первая часть создает своего рода SFINAE (хотя я никогда не видел, чтобы он использовался как это). Например, если у вас была перегрузка foo, которая делала то же самое с value2 вместо value, не было бы никакой двусмысленности для вызова. См. здесь, что я имею в виду. Сравните это с этот, который имеет только возвращаемый тип void и вызывает ошибки.

static_assert(T{}.value == 10, "Incorrect value");

Эта строка гарантирует, что инициализируемый значением экземпляр T имеет свой член value, имеет значение 10. Если это не так, генерируется ошибка компилятора с этим текстом.

} var;

Это всего лишь глобальный объект этого класса.

struct apple
{
   int value{10};
};

Это образец класса для тестирования. Он имеет член value и этот член равен 10 в инициализированном значением экземпляре (также инициализируется по умолчанию).

var.foo<apple>();

Это просто вызывает функцию.