С C ++ 17 у нас есть новое воображение 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
,
В C ++ 14 это было то же самое, но гарантированное elision делает некоторые функции вызываемыми с помощью xvalue (т.е. «T&&
«) и другие с типами значений T
,
Есть ли альтернатива, или мы должны изобрести собственную черту, чтобы справиться с этим делом?
(В теоретическом мире, где std::declval<T>
возвращенный T
вместо T&&
, is_invocable
я бы, наверное, поступил правильно).
Есть ли альтернатива, или мы должны изобрести собственную черту, чтобы справиться с этим делом?
Да, вам просто нужно написать свою собственную черту, которая не использует 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
должно быть более сложным и «делать правильные вещи» для указателей на членов и т. д. Но это по крайней мере простое приближение, которое указывает на жизнеспособность этого подхода.
Вы неправильно используете концепцию Invocable. Эта концепция означает не более, чем способность использовать std::invoke
на данную функцию и предоставленные аргументы.
Ты не можешь сделать std::invoke(f, no_move(1))
, так как это вызовет копирование / перемещение перенаправленного аргумента. Невозможно использовать значение prvalue в качестве параметра при переадресации вызова, например invoke
, Вы можете передать значение для переадресации вызова, но возможный вызов данной функции получит значение x.
Это хорошая причина избегать использования неподвижных типов в качестве параметров-значений в функциях. Возьми их const&
вместо.
C ++ не имеет черты типа, чтобы увидеть, можно ли вызывать функцию с определенными параметрами желаемым способом.