Как мы можем проверить, может ли выражение определенного типа вызываться с помощью prvalue?

С у нас есть новое воображение is_invocable и представьте новые ценности, которые на самом деле не являются ценностями.

Это позволяет вам создавать объект без необходимости сначала логически его конструировать, а затем исключать конструкцию.

Я столкнулся с проблемой, когда с помощью std::is_invocable чтобы проверить, можете ли вы что-то вызывать, и правила prvalue, кажется, сталкиваются:

struct no_move {
no_move(no_move&&)=delete;
explicit no_move(int) {}
};
void f( no_move ) {}

Теперь мы можем спросить, если f может быть вызван с использованием prvalue типа no_move?

f( no_move(1) )

std::is_invocable< decltype(&f), no_move > не работает, потому что использует std::declval<no_move>() который похож на xvalue no_move&& не тип значения no_move,

В это было то же самое, но гарантированное elision делает некоторые функции вызываемыми с помощью xvalue (т.е. «T&&«) и другие с типами значений T,

Есть ли альтернатива, или мы должны изобрести собственную черту, чтобы справиться с этим делом?

(В теоретическом мире, где std::declval<T> возвращенный T вместо T&&, is_invocable я бы, наверное, поступил правильно).

15

Решение

Есть ли альтернатива, или мы должны изобрести собственную черту, чтобы справиться с этим делом?

Да, вам просто нужно написать свою собственную черту, которая не использует declval, Если у вас есть std::is_detected валяется (что я знаю, вы, конечно, делаете)

template <typename T> T make();

template <typename F, typename... Args>
using invoke_result_t = decltype(std::declval<F>()(make<Args>()...));
//                               ^^^^^^^^^^^^^     ^^^^^

template <typename F, typename... Args>
using is_invocable = std::is_detected<invoke_result_t, F, Args...>;

Сюда, std::is_invocable<decltype(f), no_move> является false_type, но is_invocable<decltype(f), no_move)> является true_type,

Я намеренно использую declval<F>() для функции вместо make чтобы разрешить использование decltype(f) Вот. В самом деле, invoke_result_t должно быть более сложным и «делать правильные вещи» для указателей на членов и т. д. Но это по крайней мере простое приближение, которое указывает на жизнеспособность этого подхода.

3

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

Вы неправильно используете концепцию Invocable. Эта концепция означает не более, чем способность использовать std::invoke на данную функцию и предоставленные аргументы.

Ты не можешь сделать std::invoke(f, no_move(1)), так как это вызовет копирование / перемещение перенаправленного аргумента. Невозможно использовать значение prvalue в качестве параметра при переадресации вызова, например invoke, Вы можете передать значение для переадресации вызова, но возможный вызов данной функции получит значение x.

Это хорошая причина избегать использования неподвижных типов в качестве параметров-значений в функциях. Возьми их const& вместо.

C ++ не имеет черты типа, чтобы увидеть, можно ли вызывать функцию с определенными параметрами желаемым способом.

6

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