I am experimenting with some lambda detection functionality.
What I am trying to achieve is to be able to detect if I can call a lambda F with an argument of type const C&
returning a result convertible to bool
.
The code below looks close to what I need, but does not behave as expected :
#include <string>
#include <iostream>
#include <type_traits>
#include <experimental/type_traits>
template <typename F, typename C>
using is_invocable_predicate = decltype(std::declval<F>()(std::declval<const C&>()));
template <typename F, typename C>
constexpr bool can_invoke_pred_v = std::experimental::is_detected_convertible_v<bool, is_invocable_predicate, F, C> ;
int main() {
// this lambda expectedly can not be invoked with std::string argument
auto lambda = [](auto x) -> bool { return x * x; };
lambda(1); // works
//lambda(std::string("abc")); // this obviously does not compile (as there is no operator * for std::string
constexpr auto can_invoke_int = can_invoke_pred_v<decltype(lambda), int>;
static_assert(can_invoke_int); // invocable with int
// if I remove ->bool in lambda definition next line will not compile,
// otherwise the assertion fails
constexpr auto can_invoke_str = can_invoke_pred_v<decltype(lambda), std::string>;
static_assert(not can_invoke_str); // expected to fail as I cannot invoke the lambda with string
return 0;
}
If I remove -> bool
(say I define lambda as auto lambda = [](auto x) { return x * x; };
), then line static_assert(can_invoke_pred_v<decltype(lambda), std::string>);
does not compile, i.e. instead of detecting that such lambda containing x*x
expression cannot be generated for type std::string, it is generated and then I get compilation error.
test.cpp:14:41: error: no match for 'operator*' (operand types are 'std::__cxx11::basic_string<char>' and 'std::__cxx11::basic_string<char>')
14 | auto lambda = [](auto x) { return x * x; };
| ~~^~~
Is there a solution for this problem? Could someone explain what is happening here?