I am trying to implement my own is_member_function_pointer and I'm having trouble with it.
namespace __implementation
{
// integral_constant
template<typename T, T v>
struct integral_constant
{
static constexpr T result = v;
typedef integral_constant<T,v> type;
constexpr operator T() { return result; }
};
// true_type
typedef integral_constant<bool, true> true_type;
// false_type
typedef integral_constant<bool, false> false_type;
// remove_const
template<typename T> struct remove_const { typedef T type; };
template<typename T> struct remove_const<const T> { typedef T type; };
// remove_volatile
template<typename T> struct remove_volatile { typedef T type; };
template<typename T> struct remove_volatile<volatile T> { typedef T type; };
// remove_cv
template<typename T> struct remove_cv
{ typedef typename remove_volatile<typename remove_const<T>::type>::type type; };
// is_function - ugliness ahead due to variadic functions!
template<typename T, typename... Args> struct is_function : public false_type {};
template<typename T, typename... Args> struct is_function<T(Args...)> : public true_type {}; // normal function
template<typename T, typename... Args> struct is_function<T(Args......)> : public true_type {}; // variadic function
// is_member_function_pointer
template<typename T> struct is_member_function_pointer : public false_type {};
template<typename T, typename Class> struct is_member_function_pointer<T Class::*> : public is_function<T> {};
}
/*
* Short forms: either alias templates or constexpr functions
*/
// remove_const
template<typename T>
using remove_const = typename __implementation::remove_const<T>::type;
// remove_volatile
template<typename T>
using remove_volatile = typename __implementation::remove_volatile<T>::type;
// remove_cv
template<typename T>
using remove_cv = typename __implementation::remove_cv<T>::type;
// is_member_function_pointer
template<typename T>
constexpr bool is_member_function_pointer { return __implementation::is_member_function_pointer<T>::result; }
// is_function
template<typename T>
constexpr bool is_function() { return __implementation::is_function<typename __implementation::remove_cv<T>::type>::result; }
The problem lies in normal function pointers, which fail to work as they should for the member_function_pointer template. Also, const member function pointers aren't recognized as member_function_pointer, which is unfortunate. How can I fix this implementation? I believe I can enable_if a regular function pointer specialization to work around the normal function pointer problem, but I can't see a way out of the const member function pointer problem (I've literally tried adding remove_cv's and const's everywhere in the type trait definition, to no avail). I can see the current is_member_function_pointer doesn't handle a const class's member function, but I don't know what syntactical magic I can use to do so.
Any help is appreciated.
A very short talk on Chat has brought this easy solution:
// is_member_function_pointer
template<typename T> struct is_member_function_pointer : public false_type {};
template<typename T, typename Class, typename... Args> struct is_member_function_pointer<T (Class::*)(Args...)> : public true_type {};
template<typename T, typename Class, typename... Args> struct is_member_function_pointer<T (Class::*)(Args...) const> : public true_type {};
template<typename T, typename Class, typename... Args> struct is_member_function_pointer<T (Class::*)(Args...) volatile> : public true_type {};
template<typename T, typename Class, typename... Args> struct is_member_function_pointer<T (Class::*)(Args...) const volatile> : public true_type {};
Which includes specializations for volatile as well.
EDIT as #Xeo and #Johannes pointed out, I missed the ref-qualifier (aka rvalue for *this) versions:
template<typename T, typename Class, typename... Args> struct is_member_function_pointer<T (Class::*)(Args...) &> : public true_type {};
template<typename T, typename Class, typename... Args> struct is_member_function_pointer<T (Class::*)(Args...) const &> : public true_type {};
template<typename T, typename Class, typename... Args> struct is_member_function_pointer<T (Class::*)(Args...) volatile &> : public true_type {};
template<typename T, typename Class, typename... Args> struct is_member_function_pointer<T (Class::*)(Args...) const volatile &> : public true_type {};
template<typename T, typename Class, typename... Args> struct is_member_function_pointer<T (Class::*)(Args...) &&> : public true_type {};
template<typename T, typename Class, typename... Args> struct is_member_function_pointer<T (Class::*)(Args...) const &&> : public true_type {};
template<typename T, typename Class, typename... Args> struct is_member_function_pointer<T (Class::*)(Args...) volatile &&> : public true_type {};
template<typename T, typename Class, typename... Args> struct is_member_function_pointer<T (Class::*)(Args...) const volatile &&> : public true_type {};
template<typename T, typename Class, typename... Args> struct is_member_function_pointer<T (Class::*)(Args...,...)> : public true_type {};
template<typename T, typename Class, typename... Args> struct is_member_function_pointer<T (Class::*)(Args...,...) const> : public true_type {};
template<typename T, typename Class, typename... Args> struct is_member_function_pointer<T (Class::*)(Args...,...) volatile> : public true_type {};
template<typename T, typename Class, typename... Args> struct is_member_function_pointer<T (Class::*)(Args...,...) const volatile> : public true_type {};
template<typename T, typename Class, typename... Args> struct is_member_function_pointer<T (Class::*)(Args...,...) &> : public true_type {};
template<typename T, typename Class, typename... Args> struct is_member_function_pointer<T (Class::*)(Args...,...) const &> : public true_type {};
template<typename T, typename Class, typename... Args> struct is_member_function_pointer<T (Class::*)(Args...,...) volatile &> : public true_type {};
template<typename T, typename Class, typename... Args> struct is_member_function_pointer<T (Class::*)(Args...,...) const volatile &> : public true_type {};
template<typename T, typename Class, typename... Args> struct is_member_function_pointer<T (Class::*)(Args...,...) &&> : public true_type {};
template<typename T, typename Class, typename... Args> struct is_member_function_pointer<T (Class::*)(Args...,...) const &&> : public true_type {};
template<typename T, typename Class, typename... Args> struct is_member_function_pointer<T (Class::*)(Args...,...) volatile &&> : public true_type {};
template<typename T, typename Class, typename... Args> struct is_member_function_pointer<T (Class::*)(Args...,...) const volatile &&> : public true_type {};
Which is still quite doable. It's clearer then crazy template magic and numerous helper templates IMHO.
EDIT2 to clarify, the above are all in an implementation namespace and wrapped around by
template<typename T> constexpr bool
is_member_function_pointer() { return __implementation::is_member_function_pointer<remove_cv<T>>::result; }
Where remove_cv is alias template'd to the convenient
template<typenamen T> using
remove_cv = typename __implementation::remove_cv<T>::type;
I suppose there are other, and maybe better ways, but this one is at least clear to the reader without any further SFINAE tricks like applied in libc++ or libstdc++, IMHO.
Alternatively
template<typename T> struct remove_c { typedef T type; };
template<typename T> struct remove_c<T const> { typedef T type; };
template<bool C>
struct bool_ { static bool const value = C; };
template<typename T, typename U>
struct is_same : bool_<false> {};
template<typename T>
struct is_same<T, T> : bool_<true> { };
template<typename T, typename = bool_<true> >
struct is_function : bool_<false> {};
struct C { };
template<typename T>
struct is_function< T,
bool_<is_same<typename remove_c<T>::type const C::*,
typename remove_c<T>::type C::*>::value> >
: bool_<true> {};
template<typename T>
struct is_member_function_pointer_impl : bool_<false> {};
template<typename T, typename C>
struct is_member_function_pointer_impl<T C::* const volatile>
: is_function<T> {};
template<typename T>
struct is_member_function_pointer
: is_member_function_pointer_impl<T const volatile> {};
Related
Is it possible to write a type trait whose value is true for all common STL structures (e.g., vector, set, map, ...)?
To get started, I'd like to write a type trait that is true for a vector and false otherwise. I tried this, but it doesn't compile:
template<class T, typename Enable = void>
struct is_vector {
static bool const value = false;
};
template<class T, class U>
struct is_vector<T, typename boost::enable_if<boost::is_same<T, std::vector<U> > >::type> {
static bool const value = true;
};
The error message is template parameters not used in partial specialization: U.
Look, another SFINAE-based solution for detecting STL-like containers:
template<typename T, typename _ = void>
struct is_container : std::false_type {};
template<typename... Ts>
struct is_container_helper {};
template<typename T>
struct is_container<
T,
std::conditional_t<
false,
is_container_helper<
typename T::value_type,
typename T::size_type,
typename T::allocator_type,
typename T::iterator,
typename T::const_iterator,
decltype(std::declval<T>().size()),
decltype(std::declval<T>().begin()),
decltype(std::declval<T>().end()),
decltype(std::declval<T>().cbegin()),
decltype(std::declval<T>().cend())
>,
void
>
> : public std::true_type {};
Of course, you might change methods and types to be checked.
If you want to detect only STL containers (it means std::vector, std::list, etc) you should do something like this.
UPDATE. As #Deduplicator noted, container might not meet AllocatorAwareContainer requirements (e.g.: std::array<T, N>). That is why check on T::allocator_type is not neccessary. But you may check any/all Container requirements in a similar way.
You would say that it should be simpler than that...
template <typename T, typename _ = void>
struct is_vector {
static const bool value = false;
};
template <typename T>
struct is_vector< T,
typename enable_if<
is_same<T,
std::vector< typename T::value_type,
typename T::allocator_type >
>::value
>::type
>
{
static const bool value = true;
};
... But I am not really sure of whether that is simpler or not.
In C++11 you can use type aliases (I think, untested):
template <typename T>
using is_vector = is_same<T, std::vector< typename T::value_type,
typename T::allocator_type > >;
The problem with your approach is that the type U is non-deducible in the context where it is used.
Actually, after some trial and error I found it's quite simple:
template<class T>
struct is_vector<std::vector<T> > {
static bool const value = true;
};
I'd still like to know how to write a more general is_container. Do I have to list all types by hand?
While the other answers here that try to guess whether a class is a container or not might work for you, I would like to present you with the alternative of naming the type you want to return true for. You can use this to build arbitrary is_(something) traits types.
template<class T> struct is_container : public std::false_type {};
template<class T, class Alloc>
struct is_container<std::vector<T, Alloc>> : public std::true_type {};
template<class K, class T, class Comp, class Alloc>
struct is_container<std::map<K, T, Comp, Alloc>> : public std::true_type {};
And so on.
You will need to include <type_traits> and whatever classes you add to your rules.
Why not do something like this for is_container?
template <typename Container>
struct is_container : std::false_type { };
template <typename... Ts> struct is_container<std::list<Ts...> > : std::true_type { };
template <typename... Ts> struct is_container<std::vector<Ts...> > : std::true_type { };
// ...
That way users can add their own containers by partially-specializing. As for is_vector et-al, just use partial specialization as I did above, but limit it to only one container type, not many.
The way I like to detect whether something is a container is to look for data() and size() member functions. Like this:
template <typename T, typename = void>
struct is_container : std::false_type {};
template <typename T>
struct is_container<T
, std::void_t<decltype(std::declval<T>().data())
, decltype(std::declval<T>().size())>> : std::true_type {};
template <typename T>
struct is_container {
template <
typename U,
typename I = typename U::const_iterator
>
static int8_t test(U* u);
template <typename U>
static int16_t test(...);
enum { value = sizeof test <typename std::remove_cv<T>::type> (0) == 1 };
};
template<typename T, size_t N>
struct is_container <std::array<T,N>> : std::true_type { };
Fast forward to 2018 and C++17, I was so daring to improve on #Frank answer
// clang++ prog.cc -Wall -Wextra -std=c++17
#include <iostream>
#include <vector>
namespace dbj {
template<class T>
struct is_vector {
using type = T ;
constexpr static bool value = false;
};
template<class T>
struct is_vector<std::vector<T>> {
using type = std::vector<T> ;
constexpr static bool value = true;
};
// and the two "olbigatory" aliases
template< typename T>
inline constexpr bool is_vector_v = is_vector<T>::value ;
template< typename T>
using is_vector_t = typename is_vector<T>::type ;
} // dbj
int main()
{
using namespace dbj;
std::cout << std::boolalpha;
std::cout << is_vector_v<std::vector<int>> << std::endl ;
std::cout << is_vector_v<int> << std::endl ;
} /* Created 2018 by dbj#dbj.org */
The "proof the pudding". There are better ways to do this, but this works for std::vector.
We can also use concepts. I compiled this with GCC 10.1 flag -std=c++20.
#include<concepts>
template<typename T>
concept is_container = requires (T a)
{
a.begin();
// Uncomment both lines for vectors only
// a.data(); // arrays and vectors
// a.reserve(1); // narrowed down to vectors
};
In our project we still didn't manage to migrate to compiler supporting C++11, so for type_traits of container objects I had to wrote a simple boost style helper:
template<typename Cont> struct is_std_container: boost::false_type {};
template<typename T, typename A>
struct is_std_container<std::vector<T,A> >: boost::true_type {};
template<typename T, typename A>
struct is_std_container<std::list<T,A> >: boost::true_type {};
template<typename T, typename A>
struct is_std_container<std::deque<T,A> >: boost::true_type {};
template<typename K, typename C, typename A>
struct is_std_container<std::set<K,C,A> >: boost::true_type {};
template<typename K, typename T, typename C, typename A>
struct is_std_container<std::map<K,T,C,A> >: boost::true_type {};
template<typename Cont> struct is_std_sequence: boost::false_type {};
template<typename T, typename A>
struct is_std_sequence<std::vector<T,A> >: boost::true_type {};
template<typename T, typename A>
struct is_std_sequence<std::list<T,A> >: boost::true_type {};
template<typename T, typename A>
struct is_std_sequence<std::deque<T,A> >: boost::true_type {};
If you also want to make it work for const std::vector, you can use the following:
namespace local {
template<typename T, typename _ = void>
struct isVector: std::false_type {
};
template<typename T>
struct isVector<T,
typename std::enable_if<
std::is_same<typename std::decay<T>::type, std::vector<typename std::decay<T>::type::value_type, typename std::decay<T>::type::allocator_type> >::value>::type> : std::true_type {
};
}
TEST(TypeTraitTest, testIsVector) {
ASSERT_TRUE(local::isVector<std::vector<int>>::value);
ASSERT_TRUE(local::isVector<const std::vector<int>>::value);
ASSERT_FALSE(local::isVector<std::list<int>>::value);
ASSERT_FALSE(local::isVector<int>::value);
std::vector<uint8_t> output;
std::vector<uint8_t> &output2 = output;
EXPECT_TRUE(core::isVector<decltype(output)>::value);
EXPECT_TRUE(core::isVector<decltype(output2)>::value);
}
Without the std::remove_cv call the second ASSERT_TRUE would fail. But of course this depends on your needs. The thing here is that according to the specs, std::is_same checks for const and volatile to also match.
Say I have a get_at metafunction which gets the Nth type from a variadic template parameter list:
template <int I, typename ...Ts>
struct get_at;
template <int I, typename T, typename ...Ts>
struct get_at<I, T, Ts...> : public get_at<I-1, Ts...>
{
};
template <typename T, typename ...Ts>
struct get_at<0, T, Ts...> : public std::true_type
{
typedef T type;
};
template <int I>
struct get_at<I> : public std::false_type
{
};
And I'd like to store the Ts... in a list type like so:
template <typename... Ts>
struct list {};
How would I get the Ts... out of the containing list type so that I can put it into the get_at metafunction?
You don't have to. Just write another metafunction (any problem can be solved by another layer of indirection?):
template <int I, typename Seq>
struct get_at_seq;
template <int I, typename... Ts>
struct get_at_seq<I, list<Ts...>>
: get_at<I, Ts...>
{ };
Or even:
template <int I, template <typename...> class C, typename... Ts>
struct get_at_seq<I, C<Ts...>>
: get_at<I, Ts...>
{ };
A note though, inheriting from true_type or false_type doesn't make sense for this use-case. You override type, but then you still have operator bool() on get_at, which makes no sense for this usage. Better to just write in value explicitly, e.g.:
template <typename T, typename ...Ts>
struct get_at<0, T, Ts...>
{
typedef T type;
static constexpr bool value = true;
};
How can I make a class template that returns whether any of its variadic types are equal to the first type. I want to be able to do this:
is_same<T, A, B, C>::value; // true if T is one of A, B or C
And if T is equal to any one of those types, its static value member will be true, otherwise false. How can I do this?
Nice and concise with C++17:
template <class T, class... Ts>
struct is_any : std::disjunction<std::is_same<T, Ts>...> {};
And the dual:
template <class T, class... Ts>
struct are_same : std::conjunction<std::is_same<T, Ts>...> {};
A variation that uses fold expressions:
template <class T, class... Ts>
struct is_any : std::bool_constant<(std::is_same_v<T, Ts> || ...)> {};
template <class T, class... Ts>
struct are_same : std::bool_constant<(std::is_same_v<T, Ts> && ...)> {};
Use template recursion:
template<typename T, typename... Rest>
struct is_any : std::false_type {};
template<typename T, typename First>
struct is_any<T, First> : std::is_same<T, First> {};
template<typename T, typename First, typename... Rest>
struct is_any<T, First, Rest...>
: std::integral_constant<bool, std::is_same<T, First>::value || is_any<T, Rest...>::value>
{};
static_assert(is_any<int, char, double, int>::value, "error 1"); // OK
static_assert(is_any<int, char, double, short>::value, "error 2"); // error
In C++17 you have an even nicer solution, using template variables and fold expressions:
template<class T, class... Rest>
inline constexpr bool are_all_same = (std::is_same_v<T, Rest> && ...);
And the usage is also simpler than all other examples:
are_all_same<T, A, B, C>
No ::value, no parentheses!
Something like this. First, a small metaprogramming library, because it adds like 2 lines to do it generically:
template<template<typename,typename>class checker, typename... Ts>
struct is_any_to_first : std::false_type {};
template<template<typename,typename>class checker, typename T0, typename T1, typename... Ts>
struct is_any_to_first<checker, T0, T1, Ts...> :
std::integral_constant< bool, checker<T0, T1>::value || is_any_to_first<checker, T0, Ts...>::value>
{};
Then a 2 line implementation of is_any_same_to_first:
template<typename... Ts>
using is_any_same_to_first = is_any_to_first< std::is_same, Ts... >;
And for completeness, the original is_all, which may also prove useful:
template<template<typename,typename>class checker, typename... Ts>
struct is_all : std::true_type {};
template<template<typename,typename>class checker, typename T0, typename T1, typename... Ts>
struct is_all<checker, T0, T1, Ts...> :
std::integral_constant< bool, checker<T0, T1>::value && is_all<checker, T0, Ts...>::value>
{};
template<typename... Ts>
using is_all_same = is_all< std::is_same, Ts... >;
Live example of the is_all_same.
Note that calling is_any_same_to_first anything less explicit is asking for trouble. 2/3 people who tried to answer this question, including me, assumed that is_same<A,B,C> is true iff all three are the same type!
Using the relaxed C++14 constexpr functions, these kinds of things are much easier to code, and probably much faster to compile as well, so you could write:
template <class T, class ... Candidates>
constexpr bool is_all_same() {
bool pairs[] = {std::is_same<T,Candidates>::value...};
for(bool p: pairs) if(!p) return false;
return true;
}
template <class T, class ... Candidates>
constexpr bool is_any_same() {
bool pairs[] = {std::is_same<T,Candidates>::value...};
for(bool p: pairs) if(p) return true;
return false;
}
This is enabled by the fact that in C++14 constexpr functions can have for loops.
The most generic version that works :
since C++11
without dependencies (no #include <type_traits> needed)
only one name is_same works for n-types (no is_same_all needed)
template <typename First, typename Second, typename ... Next>
struct is_same {
template <typename A, typename B>
struct is_same_min {
enum { value = false };
};
template <typename A>
struct is_same_min<A,A> {
enum { value = true };
};
template <typename X, typename Y>
constexpr static bool check() {
return is_same_min<X,Y>::value;
};
template <typename X, typename Y, typename Z, typename ... K>
constexpr static bool check() {
return is_same_min<X,Y>::value and check<Y, Z, K...>();
};
enum { value = check<First, Second, Next...>() };
};
Just use is_same<T1,T2,T3...>::value
Is it possible to write a type trait, say is_callable<T> which tells if an object has an operator() defined?
It is easy if the arguments to the call operator are known in advance, but not in the general case.
I want the trait to return true if and only if there is at least one overloaded call operator defined.
This question is related and has a good answer, but it doesn't work on all types (only on int-convertible types). Also, std::is_function works, but only on proper C++ functions, not on functors. I'm looking for a more general solution.
I think this trait does what you want. It detects operator() with any kind of signature even if it's overloaded and also if it's templatized:
template<typename T>
struct is_callable {
private:
typedef char(&yes)[1];
typedef char(&no)[2];
struct Fallback { void operator()(); };
struct Derived : T, Fallback { };
template<typename U, U> struct Check;
template<typename>
static yes test(...);
template<typename C>
static no test(Check<void (Fallback::*)(), &C::operator()>*);
public:
static const bool value = sizeof(test<Derived>(0)) == sizeof(yes);
};
The principle is based on Member Detector idiom. As it is, it will fail to compile if you pass it a non-class type, but that shouldn't be hard to fix, I just left it out for brevity. You can also extend it to report true for functions.
Of course it doesn't give you any info about the signature(s) of operator() whatsoever, but I believe that's not what you asked for, right?
EDIT for Klaim:
It's simple enough to make it work (return false) with non-class types. If you rename the above class to is_callable_impl, you can write this, for example:
template<typename T>
struct is_callable
: std::conditional<
std::is_class<T>::value,
is_callable_impl<T>,
std::false_type
>::type
{ };
The answers here were helpful but I came here wanting something that could also spot whether something was callable regardless of whether it happened to be an object or a classic function. jrok's answer to this aspect of the problem, alas, didn't work because std::conditional actually evaluates the types of both arms!
So, here's a solution:
// Note that std::is_function says that pointers to functions
// and references to functions aren't functions, so we'll make our
// own is_function_t that pulls off any pointer/reference first.
template<typename T>
using remove_ref_t = typename std::remove_reference<T>::type;
template<typename T>
using remove_refptr_t = typename std::remove_pointer<remove_ref_t<T>>::type;
template<typename T>
using is_function_t = typename std::is_function<remove_refptr_t<T>>::type;
// We can't use std::conditional because it (apparently) must determine
// the types of both arms of the condition, so we do it directly.
// Non-objects are callable only if they are functions.
template<bool isObject, typename T>
struct is_callable_impl : public is_function_t<T> {};
// Objects are callable if they have an operator(). We use a method check
// to find out.
template<typename T>
struct is_callable_impl<true, T> {
private:
struct Fallback { void operator()(); };
struct Derived : T, Fallback { };
template<typename U, U> struct Check;
template<typename>
static std::true_type test(...);
template<typename C>
static std::false_type test(Check<void (Fallback::*)(), &C::operator()>*);
public:
typedef decltype(test<Derived>(nullptr)) type;
};
// Now we have our final version of is_callable_t. Again, we have to take
// care with references because std::is_class says "No" if we give it a
// reference to a class.
template<typename T>
using is_callable_t =
typename is_callable_impl<std::is_class<remove_ref_t<T>>::value,
remove_ref_t<T> >::type;
But in the end, for my application, I really wanted to just know whether you could say f() (i.e., call it with no arguments), so I instead went with something much simpler.
template <typename T>
constexpr bool noarg_callable_impl(
typename std::enable_if<bool(sizeof((std::declval<T>()(),0)))>::type*)
{
return true;
}
template<typename T>
constexpr bool noarg_callable_impl(...)
{
return false;
}
template<typename T>
constexpr bool is_noarg_callable()
{
return noarg_callable_impl<T>(nullptr);
}
In fact, I went even further. I knew the function was supposed to return an int, so rather than just check that I could call it, I checked the return type, too, by changing the enable_if to:
typename std::enable_if<std::is_convertible<decltype(std::declval<T>()()),
int>::value>::type*)
Hope this helps someone!
Here is a possible solution using C++11 that works without requiring to know the signature of the call operator for functors, but only as long the functor does not have more than one overload of operator ():
#include <type_traits>
template<typename T, typename = void>
struct is_callable : std::is_function<T> { };
template<typename T>
struct is_callable<T, typename std::enable_if<
std::is_same<decltype(void(&T::operator())), void>::value
>::type> : std::true_type { };
This is how you would use it:
struct C
{
void operator () () { }
};
struct NC { };
struct D
{
void operator () () { }
void operator () (int) { }
};
int main()
{
static_assert(is_callable<C>::value, "Error");
static_assert(is_callable<void()>::value, "Error");
auto l = [] () { };
static_assert(is_callable<decltype(l)>::value, "Error");
// Fires! (no operator())
static_assert(is_callable<NC>::value, "Error");
// Fires! (several overloads of operator ())
static_assert(is_callable<D>::value, "Error");
}
C++17 brings std::is_invocable and friends.
This answer also given a solution on how to emulate it with C++14.
There are several other answers already, of course, and they are useful, but none of them seem to cover every use case AFAICT. Borrowing from those answers and this possible implementation of std::is_function, I created a version that covers every possible use case of which I could think. It's kind of lengthy, but very feature complete (Demo).
template<typename T, typename U = void>
struct is_callable
{
static bool const constexpr value = std::conditional_t<
std::is_class<std::remove_reference_t<T>>::value,
is_callable<std::remove_reference_t<T>, int>, std::false_type>::value;
};
template<typename T, typename U, typename ...Args>
struct is_callable<T(Args...), U> : std::true_type {};
template<typename T, typename U, typename ...Args>
struct is_callable<T(*)(Args...), U> : std::true_type {};
template<typename T, typename U, typename ...Args>
struct is_callable<T(&)(Args...), U> : std::true_type {};
template<typename T, typename U, typename ...Args>
struct is_callable<T(Args......), U> : std::true_type {};
template<typename T, typename U, typename ...Args>
struct is_callable<T(*)(Args......), U> : std::true_type {};
template<typename T, typename U, typename ...Args>
struct is_callable<T(&)(Args......), U> : std::true_type {};
template<typename T, typename U, typename ...Args>
struct is_callable<T(Args...)const, U> : std::true_type {};
template<typename T, typename U, typename ...Args>
struct is_callable<T(Args...)volatile, U> : std::true_type {};
template<typename T, typename U, typename ...Args>
struct is_callable<T(Args...)const volatile, U> : std::true_type {};
template<typename T, typename U, typename ...Args>
struct is_callable<T(Args......)const, U> : std::true_type {};
template<typename T, typename U, typename ...Args>
struct is_callable<T(Args......)volatile, U> : std::true_type{};
template<typename T, typename U, typename ...Args>
struct is_callable<T(Args......)const volatile, U> : std::true_type {};
template<typename T, typename U, typename ...Args>
struct is_callable<T(Args...)&, U> : std::true_type {};
template<typename T, typename U, typename ...Args>
struct is_callable<T(Args...)const&, U> : std::true_type{};
template<typename T, typename U, typename ...Args>
struct is_callable<T(Args...)volatile&, U> : std::true_type{};
template<typename T, typename U, typename ...Args>
struct is_callable<T(Args...)const volatile&, U> : std::true_type{};
template<typename T, typename U, typename ...Args>
struct is_callable<T(Args......)&, U> : std::true_type {};
template<typename T, typename U, typename ...Args>
struct is_callable<T(Args......)const&, U> : std::true_type{};
template<typename T, typename U, typename ...Args>
struct is_callable<T(Args......)volatile&, U> : std::true_type{};
template<typename T, typename U, typename ...Args>
struct is_callable<T(Args......)const volatile&, U> : std::true_type{};
template<typename T, typename U, typename ...Args>
struct is_callable<T(Args...)&&, U> : std::true_type{};
template<typename T, typename U, typename ...Args>
struct is_callable<T(Args...)const&&, U> : std::true_type{};
template<typename T, typename U, typename ...Args>
struct is_callable<T(Args...)volatile&&, U> : std::true_type{};
template<typename T, typename U, typename ...Args>
struct is_callable<T(Args...)const volatile&&, U> : std::true_type{};
template<typename T, typename U, typename ...Args>
struct is_callable<T(Args......)&&, U> : std::true_type{};
template<typename T, typename U, typename ...Args>
struct is_callable<T(Args......)const&&, U> : std::true_type{};
template<typename T, typename U, typename ...Args>
struct is_callable<T(Args......)volatile&&, U> : std::true_type{};
template<typename T, typename U, typename ...Args>
struct is_callable<T(Args......)const volatile&&, U> : std::true_type{};
template<typename T>
struct is_callable<T, int>
{
private:
using YesType = char(&)[1];
using NoType = char(&)[2];
struct Fallback { void operator()(); };
struct Derived : T, Fallback {};
template<typename U, U>
struct Check;
template<typename>
static YesType Test(...);
template<typename C>
static NoType Test(Check<void (Fallback::*)(), &C::operator()>*);
public:
static bool const constexpr value = sizeof(Test<Derived>(0)) == sizeof(YesType);
};
This works correctly with non-class types (returns false, of course), function types (<T()>), function pointer types, function reference types, functor class types, bind expressions, lambda types, etc. This works correctly even if the class constructor is private and/or non-defaulted, and even if operator() is overloaded. This returns false for member function pointers by design because they are not callable, but you can use bind to create a callable expression.
Note: These assume that the default constructor is valid for the type your checking. Not sure offhand how to get around that.
The following seems to work if it's callable with 0 arguments. Is there something in is_function's implementation that might help to extend this to 1 or more argument callables?:
template <typename T>
struct is_callable {
// Types "yes" and "no" are guaranteed to have different sizes,
// specifically sizeof(yes) == 1 and sizeof(no) == 2.
typedef char yes[1];
typedef char no[2];
template <typename C>
static yes& test(decltype(C()())*);
template <typename>
static no& test(...);
// If the "sizeof" the result of calling test<T>(0) would be equal to the sizeof(yes),
// the first overload worked and T has a nested type named foobar.
static const bool value = sizeof(test<T>(0)) == sizeof(yes);
};
If you know the type of the argument (even if it's a template parameter), the following would work for 1 argument, and I imagine one could extend pretty easily from there:
template <typename T, typename T2>
struct is_callable_1 {
// Types "yes" and "no" are guaranteed to have different sizes,
// specifically sizeof(yes) == 1 and sizeof(no) == 2.
typedef char yes[1];
typedef char no[2];
template <typename C>
static yes& test(decltype(C()(T2()))*);
template <typename, typename>
static no& test(...);
// If the "sizeof" the result of calling test<T>(0) would be equal to the sizeof(yes),
// the first overload worked and T has a nested type named foobar.
static const bool value = sizeof(test<T>(0)) == sizeof(yes);
};
Edit
here is a modification that handles the case where default constructor isn't available.
This is a neat and short trick for finding if T is callable. It goes along the lines originally proposed by Walter E. Brown at CPPCON'14 in his talk on modern template metaprogramming.
template <class... >
using void_t = void;
template <class T>
using has_opr_t = decltype(&T::operator());
template <class T, class = void>
struct is_callable : std::false_type { };
template <class T>
struct is_callable<T, void_t<has_opr_t<typename std::decay<T>::type>>> : std::true_type { };
Here is another implementation.
It makes use of std::is_function template for free functions.
For classes, it uses something similar to the Member Detector Idiom. If T has a call operator, callable_2 will contain more than one operator(). This will cause the first can_call function to be discarded (through SFINAE) due to ambiguity failure in decltype(&callable_2<T>::operator()) and the second can_call function will return true. If T does not have a call operator, the first can_call function will be used (due to overload resolution rules).
namespace impl
{
struct callable_1 { void operator()(); };
template<typename T> struct callable_2 : T, callable_1 { };
template<typename T>
static constexpr bool can_call(decltype(&callable_2<T>::operator())*) noexcept { return false; }
template<typename>
static constexpr bool can_call(...) noexcept { return true; }
template<bool is_class, typename T>
struct is_callable : public std::is_function<T> { };
template<typename T> struct is_callable<false, T*> : public is_callable<false, T> { };
template<typename T> struct is_callable<false, T* const> : public is_callable<false, T> { };
template<typename T> struct is_callable<false, T* volatile> : public is_callable<false, T> { };
template<typename T> struct is_callable<false, T* const volatile> : public is_callable<false, T> { };
template<typename T>
struct is_callable<true, T> : public std::integral_constant<bool, can_call<T>(0)> { };
}
template<typename T>
using is_callable = impl::is_callable<std::is_class<std::remove_reference_t<T>>::value,
std::remove_reference_t<T>>;
Consider this struct:
struct foo {
void dummy() const {}
};
Is it possible to detect the constness of this method using SFINAE?
For example, I would like to capture this property in a trait that could be usable in a static_assert:
static_assert(is_const_method<decltype(&foo::dummy)>::value, "Not const!");
I thought that either std::is_const or std::remove_const would help me here but they don't seem to encompass this "type" of constness.
Thanks,
Sure, looks like this:
#include <type_traits>
template <class T>
struct is_const_method
: std::false_type
{
};
template <class R, class C, class ...T>
struct is_const_method<R (C::*)(T...)>
: std::false_type
{
};
template <class R, class C, class ...T>
struct is_const_method<R (C::*)(T...) const>
: std::true_type
{
};
template <class R, class C, class ...T>
struct is_const_method<R (C::*)(T...) volatile>
: std::false_type
{
};
template <class R, class C, class ...T>
struct is_const_method<R (C::*)(T...) const volatile>
: std::true_type
{
};
template <class R, class C, class ...T>
struct is_const_method<R (C::*)(T...) &>
: std::false_type
{
};
template <class R, class C, class ...T>
struct is_const_method<R (C::*)(T...) const &>
: std::true_type
{
};
template <class R, class C, class ...T>
struct is_const_method<R (C::*)(T...) volatile &>
: std::false_type
{
};
template <class R, class C, class ...T>
struct is_const_method<R (C::*)(T...) const volatile &>
: std::true_type
{
};
template <class R, class C, class ...T>
struct is_const_method<R (C::*)(T...) &&>
: std::false_type
{
};
template <class R, class C, class ...T>
struct is_const_method<R (C::*)(T...) const &&>
: std::true_type
{
};
template <class R, class C, class ...T>
struct is_const_method<R (C::*)(T...) volatile &&>
: std::false_type
{
};
template <class R, class C, class ...T>
struct is_const_method<R (C::*)(T...) const volatile &&>
: std::true_type
{
};
struct foo {
void dummy() const {}
};
int main()
{
static_assert(is_const_method<decltype(&foo::dummy)>::value, "Not const!");
}
You can just use partial specializations.
// false by default
template <typename Fun>
struct is_const_function : std::false_type {};
// breakdown member function type
template <typename Class, typename Result, typename... Args>
struct is_const_function<Result (Class::*)(Args...) const> : std::true_type {};
template <typename Class, typename Result, typename... Args>
struct is_const_function<Result (Class::*)(Args...) const volatile> : std::true_type {};
// consider ref-qualified ones for compilers that support it
template <typename Class, typename Result, typename... Args>
struct is_const_function<Result (Class::*)(Args...) const&> : std::true_type {};
template <typename Class, typename Result, typename... Args>
struct is_const_function<Result (Class::*)(Args...) const&&> : std::true_type {};
template <typename Class, typename Result, typename... Args>
struct is_const_function<Result (Class::*)(Args...) const volatile&> : std::true_type {};
template <typename Class, typename Result, typename... Args>
struct is_const_function<Result (Class::*)(Args...) const volatile&&> : std::true_type {};
You could also add more specializations to catter for C-style variadic functions, but frankly, my dear, I don't give a damn.