Reputation: 1573
I'm looking for a trait to detect and to extract the full signature (to check for method qualifiers volatile
and const
) of a templated operator()
.
Which means std::bind
expressions (without the use of std::is_bind_expression
) and lambdas with auto parameters.
The expected return type and arguments are known.
For example something like:
template<typename Fn, typename T>
struct is_templated_functor { ... };
auto fun = [](auto) mutable { };
using ty = decltype(&decltype(fun)::operator()<int>);
// ty = void(decltype(fun)::*)(int)
// lambda is mutable ~~~~~~~~~~~~~~~^^^^^^
is_templated_functor<void(int), decltype(fun)>::value == true;
auto fun2 = std::bind([](int) { });
using ty2 = decltype(&decltype(fun2)::operator()<int>);
// ty2 = void(decltype(fun2)::*)(int) const
is_templated_functor<void(int), decltype(fun2)>::value == true;
Upvotes: 0
Views: 178
Reputation: 1573
Due to @Yakk's comment i realized that i don't need to get the full signature of the expression to check if the expression is callable with a const
and/or volatile
qualifier, since the return type and arguments are known already.
Its possible to use a detection idiome to check if the object with a templated operator()
is callable with the given quaifiers:
template<typename Fn>
struct impl_is_callable_with_qualifiers;
template<typename ReturnType, typename... Args>
struct impl_is_callable_with_qualifiers<ReturnType(Args...)>
{
template<typename T>
static auto test(int)
-> typename std::is_convertible<
decltype(std::declval<T&>()(std::declval<Args>()...)),
ReturnType
>;
template<typename T>
static auto test(...)
-> std::false_type;
};
template<bool Condition, typename T>
using add_const_if_t = typename std::conditional<
Condition,
typename std::add_const<T>::type,
T
>::type;
template<bool Condition, typename T>
using add_volatile_if_t = typename std::conditional<
Condition,
typename std::add_volatile<T>::type,
T
>::type;
template<typename T, typename Fn, bool Constant, bool Volatile>
using is_callable_with_qualifiers = decltype(impl_is_callable_with_qualifiers<Fn>::template test<
add_volatile_if_t<Volatile, add_const_if_t<Constant, typename std::decay<T>::type>>
>(0));
Usage example:
struct callable
{
void huhu(int) const { }
};
auto fun = [](auto) mutable { };
static_assert(is_callable_with_qualifiers<decltype(fun), void(int), false, false>::value, "1 failed");
static_assert(!is_callable_with_qualifiers<decltype(fun), void(int), true, true>::value, "2 failed");
auto fun2 = std::bind(&callable::huhu, callable{}, std::placeholders::_1);
// std::bind isn't const correct anyway...
static_assert(is_callable_with_qualifiers<decltype(fun2), void(int), false, false>::value, "3 failed");
static_assert(is_callable_with_qualifiers<decltype(fun2), void(int), true, false>::value, "4 failed");
static_assert(!is_callable_with_qualifiers<decltype(fun2), void(int), true, true>::value, "5 failed");
Upvotes: 1