Ответ 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>();
Это просто вызывает функцию.