Static detection of any overloaded operator() [duplicate] - c++

This question already has answers here:
Find out whether a C++ object is callable
(8 answers)
Closed 7 years ago.
I use the following way, presented in a stackoverflow answer to determine whether a type is callable or not:
template <typename T>
struct is_callable
{
typedef char (& yes)[1];
typedef char (& no)[2];
// we need a template here to enable SFINAE
template <typename U>
static yes deduce(char (*)[sizeof(&U::operator())]);
// fallback
template <typename> static no deduce(...);
static bool constexpr value = std::is_function<T>::value || (sizeof(deduce<T>(0)) == sizeof(yes));
};
However it fails when a class has more than one overload of operator():
#include <iostream>
template <typename T>
class A
{
T operator()();
T operator()(T a);
T operator()(T a, T b);
};
std::cout << is_callable<A<int>>::value; // false
Is it possible to determine whether a type has any variant (templated or not, one or multiple) of overloaded operator()?

First of all you need to declare A as a full type (A<int> for example).
It's not relyable to check if an object is invokeable or not just through unwrapping and comparing it's operator() because it will fail on templated or overloaded functors.
Im using the following piece of code
to detect if an object is callable with a given function signature (ReturnType(Arguments...))
This works also for overloaded or templated operator()'s since the code tries to invoke the object with the given parameters
instead of comparing the signature of it's unwrapped operator().
As small addition the object can also be checked if it is invokeable from a const, volatile or rvalue context.
#include <type_traits>
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<bool Condition, typename T>
using add_lvalue_if_t = typename std::conditional<
Condition,
typename std::add_lvalue_reference<T>::type,
T
>::type;
template<typename T, typename Fn, bool Const, bool Volatile, bool RValue>
using is_callable_with_qualifiers = decltype(impl_is_callable_with_qualifiers<Fn>::template test<
add_lvalue_if_t<!RValue,
add_volatile_if_t<Volatile,
add_const_if_t<Const,
typename std::decay<T>::type>>>
>(0));
It is not possible to determine whether a type has any variant of overloaded operator(),
however you can test for a specific type or perform tests for multiple types to detect "possible" templates.
An example which covers the code from your question would be:
#include <iostream>
template<typename T>
class A
{
public:
A() = default;
T operator()() { return T(); }
T operator()(T a) { return T(); }
T operator()(T a, T b) { return T(); }
};
template <typename TheClass, typename T>
using is_callable = is_callable_with_qualifiers<TheClass, T(T), false, false, false>;
int main()
{
std::cout << is_callable<A<int>, int>::value; // true
}
Demo

If you just need to check if smth is callable - try to call it and see what happens:
template <typename T, typename RetType = decltype(std::declval<T>()())>
constexpr bool check_is_callable(int)
{
return true;
}
template <typename>
constexpr bool check_is_callable(...)
{
return false;
}
template <typename T>
constexpr bool is_callable()
{
return check_is_callable<T>(0);
}
Here std::declval<T>() is getting the object of T type, std::declval<T>()() is attempt to call the object of T type, and if it succeeds, RetType = decltype(std::declval<T>()()) gets the return type of call. If it does not, SFIANE lets drop to the other function overload.

Related

How to detect if a function exists?

I'm trying to detect if a specific overload for my function is callable. I assumed I could do something similar to this answer, but I believe the issue is that the function signature template<typename From, typename To> convert(const From&) is well defined, but the instantiation is not.
#include <iostream>
#include <string>
template<typename From, typename To>
To convert(const From& from)
{
// I have a lot of additional template specializations for this function
return from;
}
template<typename From, typename To>
struct IsConvertible
{
template<typename = decltype(convert<From, To>(From()))>
static std::true_type test(int);
template<typename T>
static std::false_type test(...);
static bool const value = decltype(test(0))::value;
};
int main()
{
std::cout << "IsConvertible=" << IsConvertible<int, float>::value << std::endl;
// Returns 1 as expected
std::cout << "IsConvertible=" << IsConvertible<int, std::string>::value << std::endl;
// Returns 1, expected 0. The issue seems to be that decltype(convert<From, To>(From()))
// is somehow ok, although convert<int, std::string>(1) definitly isn't
}
I want to use IsConvertible for some additional metaprogramming. Is it possible to detect if the template<typename From, typename To> To convert(const From&) function is actually callable?`
With declaration of
template<typename From, typename To> To convert(const From& from);
Your traits
template<typename From, typename To>
struct IsConvertible
would always detect presence of convert function.
One way to fix it is overloads and/or SFINAE:
template <typename> struct Tag{};
int convertImpl(tag<int>, const std::string& from);
float convertImpl(tag<float>, const std::string& from);
// overloads ...
template<typename From, typename To>
auto convert(const From& from)
-> decltype(convertImpl(tag<To>{}, from))
{
return convertImpl(tag<To>{}, from);
}
I might have misunderstood your question but is not the using std::is_invocable enough in this case as showcased in the following?
#include<type_traits>
template<typename From, typename To>
To convert(const From& from)
{
// I have a lot of additional template specializations for this function
return from;
}
template<>
std::string convert(const int& from)
{
//silly specialization
return "2"+from;
}
struct Foo{
int bar;
};
int main()
{
//ok specialization is called
std::cout<<std::is_invocable<decltype(convert<int,std::string>),std::string>::value<<std::endl;
//no way I can convert int to Foo, specialization required
std::cout<<std::is_invocable<decltype(convert<int,Foo>),Foo>::value<<std::endl;
return 0;
}
I see some problems in your code.
Without a particular order...
(1) SFINAE, using decltype(), check only the presence of a declared function; doesn't check if that function is defined or if it's definition works (compile) or not.
I propose you to rewrite convert() using directly SFINAE to declare it only when is compilable
template <typename To, typename From,
decltype( To(std::declval<From>()), bool{} ) = true>
To convert (From const & f)
{ return f; }
This way convert() is declared only if you can construct a To object starting from a From object.
(2) Observe that I've also switched the order of To and From: this way you can call the convert() function explicating only the To type
convert<float>(0); // From is deduced as int from the 0 value
If you declare To (that isn't deducible) after From (that is deducible), you necessarily have to explicit both types, calling the function, also when the From type is deducible.
(3) Your IsConvertible struct doesn't works.
It's a common error using SFINAE.
When you write
template<typename = decltype(convert<From, To>(From()))>
static std::true_type test(int);
you're trying enable/disable this test() method using SFINAE over From and To that are the template parameters of the struct
Wrong.
SFINAE works over template parameters of the method itself.
If you want to use SFINAE, you have to transform From and To in template parameters of the method; by example
template <typename F = From, typename T = To,
typename = decltype(convert<F, T>(std::declval<F>()))>
static std::true_type test(int);
Now SFINAE uses F and T that are template parameters of the test() method and this is correct.
(4) Observe that I've written std::declval<F>() instead of F(). It's because you're not sure that F (From) is default constructible. With std::declval() you go around this problem.
I propose a different IsConvertible custom type traits that take in count the From/To inversion and demand to the value call of test() the From+To->F+T type conversion
template <typename To, typename From>
struct IsConvertible
{
template <typename T, typename F,
typename = decltype(convert<T>(std::declval<F>()))>
static std::true_type test(int);
template <typename...>
static std::false_type test(...);
static bool const value = decltype(test<To, From>(0))::value;
};
(5) you're expecting that
IsConvertible<int, std::string>::value
is zero; but you forgetting that std::string is constructible from int; so this value (or IsConvertible<std::string, int>, switching To and From) should be one.
The following is a corrected full working example
#include <iostream>
#include <string>
#include <vector>
template <typename To, typename From,
decltype( To(std::declval<From>()), bool{} ) = true>
To convert (From const & f)
{ return f; }
template <typename To, typename From>
struct IsConvertible
{
template <typename T, typename F,
typename = decltype(convert<T>(std::declval<F>()))>
static std::true_type test(int);
template <typename...>
static std::false_type test(...);
static bool const value = decltype(test<To, From>(0))::value;
};
int main ()
{
std::cout << "IsConvertible=" << IsConvertible<float, int>::value
<< std::endl;
std::cout << "IsConvertible=" << IsConvertible<int, std::string>::value
<< std::endl;
}

How to test if a method is const?

How can I get a boolean value indicating if a known method has the const qualifier or not?
For example:
struct A {
void method() const {}
};
struct B {
void method() {}
};
bool testA = method_is_const<A::method>::value; // Should be true
bool testB = method_is_const<B::method>::value; // Should be false
In the type_traits header I found an is_const test I could use, but I need the method type, and I'm unsure how to obtain that.
I tried: std::is_const<decltype(&A::method)>::value but it doesn't work, and I can understand why (void (*ptr)() const) != const void (*ptr)()).
It is a lot simpler to check whether a member function can be called on a const-qualified lvalue.
template<class T>
using const_lvalue_callable_foo_t = decltype(std::declval<const T&>().foo());
template<class T>
using has_const_lvalue_callable_foo = std::experimental::is_detected<const_lvalue_callable_foo_t, T>;
Rinse and repeat, except with std::declval<const T>(), to check if said function can be called on a const-qualified rvalue. I can think of no good use cases for const && member functions, so whether there's a point in detecting this case is questionable.
Consult the current Library Fundamentals 2 TS working draft on how to implement is_detected.
It is a lot more convoluted to check whether a particular pointer-to-member-function type points to a function type with a particular cv-qualifier-seq. That requires 6 partial specializations per cv-qualifier-seq (const and const volatile are different cv-qualifier-seqs), and still can't handle overloaded member functions or member function templates. Sketching the idea:
template<class T>
struct is_pointer_to_const_member_function : std::false_type {};
template<class R, class T, class... Args>
struct is_pointer_to_const_member_function<R (T::*)(Args...) const> : std::true_type {};
template<class R, class T, class... Args>
struct is_pointer_to_const_member_function<R (T::*)(Args...) const &> : std::true_type {};
template<class R, class T, class... Args>
struct is_pointer_to_const_member_function<R (T::*)(Args...) const &&> : std::true_type {};
template<class R, class T, class... Args>
struct is_pointer_to_const_member_function<R (T::*)(Args..., ...) const> : std::true_type {};
template<class R, class T, class... Args>
struct is_pointer_to_const_member_function<R (T::*)(Args..., ...) const &> : std::true_type {};
template<class R, class T, class... Args>
struct is_pointer_to_const_member_function<R (T::*)(Args..., ...) const &&> : std::true_type {};
If you want const volatile to be true too, stamp out another 6 partial specializations along these lines.
The reason std::is_const<decltype(&A::method)>::value doesn't work is that a const member function isn't a const (member function). It's not a top-level const in the way that it would be for const int vs int.
What we can do instead is a type trait using void_t that tests whether we can call method on a const T:
template <typename... >
using void_t = void;
template <typename T, typename = void>
struct is_const_callable_method : std::false_type { };
template <typename T>
struct is_const_callable_method<T, void_t<
decltype(std::declval<const T&>().method())
> > : std::true_type { };
Demo
In C++20, things get a lot easier because concepts have been standardized, which subsumes the detection idiom.
Now all we need to write is this constraint:
template<class T>
concept ConstCallableMethod = requires(const T& _instance) {
{ _instance.method() }
};
ConstCallableMethod tests that the expression _instance.has_method() is well formed given that _instance is a const-reference type.
Given your two classes:
struct A {
void method() const { }
};
struct B {
void method() { }
};
The constraint will be true for A (ConstCallableMethod<A>) and false for B.
If you wish to also test that the return type of the method function is void, you can add ->void to the constraint like so:
template<class T>
concept ConstCallableMethodReturnsVoid = requires(const T& _instance) {
{ _instance.method() } -> void
};
If you wish to be a little more generic, you can pass in a member function pointer to the concept and test if that function pointer can be called with a const instance (although this gets a little less useful when you have overloads):
template<class T, class MemberF>
concept ConstCallableMemberReturnsVoid = requires(const T& _instance, MemberF _member_function) {
{ (_instance.*_member_function)() } -> void
};
You'd call it like so:
ConstCallableMemberReturnsVoid<A, decltype(&A::method)>
This allows for some other theoretical class like C, that has a const method, but it's not named method:
struct C
{
void foobar() const{}
};
And we can use the same concept to test:
ConstCallableMemberReturnsVoid<C, decltype(&C::foobar)>
Live Demo
Create a type trait to determine the const-ness of a method:
template<typename method_t>
struct is_const_method;
template<typename CClass, typename ReturnType, typename ...ArgType>
struct is_const_method< ReturnType (CClass::*)(ArgType...)>{
static constexpr bool value = false;
};
template<typename CClass, typename ReturnType, typename ...ArgType>
struct is_const_method< ReturnType (CClass::*)(ArgType) const>{
static constexpr bool value = true;
};

Is an is_functor C++ trait class possible?

How can I deduce statically if an argument is a C++ function object (functor)?
template <typename F>
void test(F f) {}
I tried is_function<F>::value, but this doesn't work. It also seems there is no is_functor trait, so perhaps it's not possible. I appear to be only looking for a specific member function, in this case the function call operator: F::operator().
It is possible to create such a trait, with two restrictions:
For the compiler, a free function is something fundamentally different from a class functor that overloads operator(). Thus we have to treat both cases seperately when implementing. This is not a problem for usage though, we can hide this implementation detail from the user.
We need to know the signature of the function you want to call. This is usually not a problem, and it does have the nice side effect that our trait is able to handle overloads pretty natively.
Step one: Free functions
Let's start with free functions, because they are little easier to detect. Our task is, when given a function pointer, to determine whether the signature of that function pointer matches the signature passed as the second template argument. To be able to compare those, we either need to get a grasp of the underlying function signature, or create a function pointer of our signature. I arbitrarily chose the latter:
// build R (*)(Args...) from R (Args...)
// compile error if signature is not a valid function signature
template <typename, typename>
struct build_free_function;
template <typename F, typename R, typename ... Args>
struct build_free_function<F, R (Args...)>
{ using type = R (*)(Args...); };
Now all that's left to do is to compare and we are done with the free function part:
// determine whether a free function pointer F has signature S
template <typename F, typename S>
struct is_function_with_signature
{
// check whether F and the function pointer of S are of the same
// type
static bool constexpr value = std::is_same<
F, typename build_free_function<F, S>::type
>::value;
};
Step two: Class functors
This one is a little more involved. We could easily detect with SFINAE whether a class defines an operator():
template <typename T>
struct defines_functor_operator
{
typedef char (& yes)[1];
typedef char (& no)[2];
// we need a template here to enable SFINAE
template <typename U>
static yes deduce(char (*)[sizeof(&U::operator())]);
// fallback
template <typename> static no deduce(...);
static bool constexpr value = sizeof(deduce<T>(0)) == sizeof(yes);
};
but that does not tell us whether one exists for our desired function signature! Luckily, we can use a trick here: pointers are valid template parameters. Thus we can first use the member function pointer of our desired signature, and check whether &T::operator() is of that type:
template <typename T, T> struct check;
Now check<void (C::*)() const, &C::operator()> will only be a valid template instantiation if C does indeed have a void C::operator()() const. But to do this we first have to combine C and the signature to a member function pointer. As we already have seen, we need to worry about two extra cases we did not have to care about for free functions: const and volatile functions. Besides that it's pretty much the same:
// build R (C::*)(Args...) from R (Args...)
// R (C::*)(Args...) const from R (Args...) const
// R (C::*)(Args...) volatile from R (Args...) volatile
// compile error if signature is not a valid member function signature
template <typename, typename>
struct build_class_function;
template <typename C, typename R, typename ... Args>
struct build_class_function<C, R (Args...)>
{ using type = R (C::*)(Args...); };
template <typename C, typename R, typename ... Args>
struct build_class_function<C, R (Args...) const>
{ using type = R (C::*)(Args...) const; };
template <typename C, typename R, typename ... Args>
struct build_class_function<C, R (Args...) volatile>
{ using type = R (C::*)(Args...) volatile; };
Putting that and our findings concerning the check helper struct together, we get our check metafunction for functor objects:
// determine whether a class C has an operator() with signature S
template <typename C, typename S>
struct is_functor_with_signature
{
typedef char (& yes)[1];
typedef char (& no)[2];
// helper struct to determine that C::operator() does indeed have
// the desired signature; &C::operator() is only of type
// R (C::*)(Args...) if this is true
template <typename T, T> struct check;
// T is needed to enable SFINAE
template <typename T> static yes deduce(check<
typename build_class_function<C, S>::type, &T::operator()> *);
// fallback if check helper could not be built
template <typename> static no deduce(...);
static bool constexpr value = sizeof(deduce<C>(0)) == sizeof(yes);
};
Step three: Putting the pieces together
We are almost done. Now we only need to decide when to use our free function, and when the class functor metafunctions. Luckily, C++11 provides us with a std::is_class trait that we can use for this. So all we have to do is specialize on a boolean parameter:
// C is a class, delegate to is_functor_with_signature
template <typename C, typename S, bool>
struct is_callable_impl
: std::integral_constant<
bool, is_functor_with_signature<C, S>::value
>
{};
// F is not a class, delegate to is_function_with_signature
template <typename F, typename S>
struct is_callable_impl<F, S, false>
: std::integral_constant<
bool, is_function_with_signature<F, S>::value
>
{};
So we can finally add the last piece of the puzzle, being our actual is_callable trait:
// Determine whether type Callable is callable with signature Signature.
// Compliant with functors, i.e. classes that declare operator(); and free
// function pointers: R (*)(Args...), but not R (Args...)!
template <typename Callable, typename Signature>
struct is_callable
: is_callable_impl<
Callable, Signature,
std::is_class<Callable>::value
>
{};
Now we clean up our code, put implementation details into anonymous namespaces so they are not acessible outside of our file, and have a nice is_callable.hpp to use in our project.
Full code
namespace // implementation detail
{
// build R (*)(Args...) from R (Args...)
// compile error if signature is not a valid function signature
template <typename, typename>
struct build_free_function;
template <typename F, typename R, typename ... Args>
struct build_free_function<F, R (Args...)>
{ using type = R (*)(Args...); };
// build R (C::*)(Args...) from R (Args...)
// R (C::*)(Args...) const from R (Args...) const
// R (C::*)(Args...) volatile from R (Args...) volatile
// compile error if signature is not a valid member function signature
template <typename, typename>
struct build_class_function;
template <typename C, typename R, typename ... Args>
struct build_class_function<C, R (Args...)>
{ using type = R (C::*)(Args...); };
template <typename C, typename R, typename ... Args>
struct build_class_function<C, R (Args...) const>
{ using type = R (C::*)(Args...) const; };
template <typename C, typename R, typename ... Args>
struct build_class_function<C, R (Args...) volatile>
{ using type = R (C::*)(Args...) volatile; };
// determine whether a class C has an operator() with signature S
template <typename C, typename S>
struct is_functor_with_signature
{
typedef char (& yes)[1];
typedef char (& no)[2];
// helper struct to determine that C::operator() does indeed have
// the desired signature; &C::operator() is only of type
// R (C::*)(Args...) if this is true
template <typename T, T> struct check;
// T is needed to enable SFINAE
template <typename T> static yes deduce(check<
typename build_class_function<C, S>::type, &T::operator()> *);
// fallback if check helper could not be built
template <typename> static no deduce(...);
static bool constexpr value = sizeof(deduce<C>(0)) == sizeof(yes);
};
// determine whether a free function pointer F has signature S
template <typename F, typename S>
struct is_function_with_signature
{
// check whether F and the function pointer of S are of the same
// type
static bool constexpr value = std::is_same<
F, typename build_free_function<F, S>::type
>::value;
};
// C is a class, delegate to is_functor_with_signature
template <typename C, typename S, bool>
struct is_callable_impl
: std::integral_constant<
bool, is_functor_with_signature<C, S>::value
>
{};
// F is not a class, delegate to is_function_with_signature
template <typename F, typename S>
struct is_callable_impl<F, S, false>
: std::integral_constant<
bool, is_function_with_signature<F, S>::value
>
{};
}
// Determine whether type Callable is callable with signature Signature.
// Compliant with functors, i.e. classes that declare operator(); and free
// function pointers: R (*)(Args...), but not R (Args...)!
template <typename Callable, typename Signature>
struct is_callable
: is_callable_impl<
Callable, Signature,
std::is_class<Callable>::value
>
{};
Ideone example with some tests
http://ideone.com/7PWdiv
Although this does not work for overloaded functions, for all other cases (free functions, classes implementing operator(), and lambdas) this short solutions works in C++11:
template <typename T, typename Signature>
struct is_callable: std::is_convertible<T,std::function<Signature>> { };
Note: std::is_invocable is available since C++17.
You can use the following concept in c++20
template<typename F>
concept FunctionObject = requires (F) {
&F::operator();
};
Is an is_functor C++ trait class possible?
Yes, it is possible to manually implement a validation for functors.
I tried is_function::value, but this doesn't work.
You are on the right path, it is possible to implement using std::function
Remember that std::function also accepts functions, function pointers and functor instances in its constructor.
Example:
struct Test {
public:
bool operator()(int){
return true;
}
};
void test(int){
}
void example(std::function<void(int)> ex){
cout << "Called" << endl;
};
int main()
{
example(test);
example(&test);
example(Test{});
}
That said, the logic that will be used to validate if a class has a function call overload operator (functor) is similar to the code above.
That is, if the std::function<void(int)> accepts an instance of the class Test{} means the class has a functor, otherwise it doesn't.
Example of an possible solution
Here is the source code:
//F: Test class
//Args...: The arguments, ex: int or none
template <typename F, typename... Args>
struct is_functor :
is_constructible <
function<void(Args ...)>, F
>
{};
Example usage:
is_functor<Test, int> -> True result
is_functor -> False result
Info about std::is_constructible
Is a trait class that identifies whether T is a constructible type with the set of argument types specified by Arg.
For this class, a constructible type is a type that can be constructed using a particular set of arguments.
is_constructible inherits from integral_constant as being either true_type or false_type, depending on whether T is constructible with the list of arguments Args.
In short, it checks if a given class has a constructor, for example:
struct Test2 {
Test(bool, int){}
};
std::is_constructible<Test2, bool, int> -> True result
std::is_constructible<Test2, float> -> False result
Example of implementation:
template <typename, typename, typename ...Args>
struct is_constructible_impl : false_type {};
template <typename T, typename ...Args>
struct is_constructible_impl <
void_t<decltype(T(std::declval<Args>()...))>, T, Args...
> : true_type {};
template <typename T, typename ...Args>
struct is_constructible : is_constructible_impl<void_t<>, T, Args...> {};
Final explanation
In the implementation of is_functor it was checked if std::function<void(int)> accepts an instance of Test{}, which is true.
References:
How is std::is_constructible<T, Args> implemented?
Can std::is_invocable be emulated within C++11?
https://replit.com/#LUCASP6/RowdyAlphanumericCode#main.cpp
template<typename T, typename Sign>
struct is_functor
{
typedef char yes[1];
typedef char no [2];
template <typename U, U> struct type_check;
template <typename _1> static yes &chk(type_check<Sign, &_1::operator()>*);
template <typename > static no &chk(...);
static bool const value = sizeof(chk<T>(nullptr)) == sizeof(yes);
};
Altered from this answer.
It could be used like...
template<typename T>
typename std::enable_if<is_functor<T, void(T::*)()>::value>::type func()
{
}

How to check if a template parameter is an iterator type or not?

template<class T>
struct is_iterator
{
static const bool value = ??? // What to write ???
};
int main()
{
assert(false == is_iterator<int>::value);
assert(true == is_iterator<vector<int>::iterator>::value);
assert(true == is_iterator<list<int>::iterator>::value);
assert(true == is_iterator<string::iterator>::value);
assert(true == is_iterator<char*>::value); // a raw pointer is also an iterator
}
The question is: How to make the five assert statements pass?
How about something like this?
template<typename T, typename = void>
struct is_iterator
{
static constexpr bool value = false;
};
template<typename T>
struct is_iterator<T, typename std::enable_if<!std::is_same<typename std::iterator_traits<T>::value_type, void>::value>::type>
{
static constexpr bool value = true;
};
example:
#include <iostream>
#include <type_traits>
#include <vector>
template<typename T, typename = void>
struct is_iterator
{
static constexpr bool value = false;
};
template<typename T>
struct is_iterator<T, typename std::enable_if<!std::is_same<typename std::iterator_traits<T>::value_type, void>::value>::type>
{
static constexpr bool value = true;
};
int main()
{
static_assert(!is_iterator<int>::value);
static_assert(is_iterator<int*>::value);
static_assert(is_iterator<std::vector<int>::iterator>::value);
}
http://liveworkspace.org/code/7dcf96c97fd0b7a69f12658fc7b2693e
Coming in here a few years later, where C++11 and C++14 make it a lot easier to do such things. An iterator is, at its core, something that is dereferencable, incrementable. If it's an input iterator, then also comparable. Let's go with the latter - since that looks like what you want.
The simplest version would be to use void_t:
template <typename... >
using void_t = void;
Base case:
template <typename T, typename = void>
struct is_input_iterator : std::false_type { };
Valid case specialization:
template <typename T>
struct is_input_iterator<T,
void_t<decltype(++std::declval<T&>()), // incrementable,
decltype(*std::declval<T&>()), // dereferencable,
decltype(std::declval<T&>() == std::declval<T&>())>> // comparable
: std::true_type { };
Alias:
template <typename T>
using is_input_iterator_t = typename is_input_iterator<T>::type;
No need to rely on iterator_category or using the tedious C++03 style of check things using overload resolution. Expression SFINAE is where it's at.
As Mr. Wakely points out in the comments, [iterator.traits] requires that:
it is required that if Iterator is the type of
an iterator, the types
iterator_traits<Iterator>::difference_type
iterator_traits<Iterator>::value_type
iterator_traits<Iterator>::iterator_category
be defined as the iterator’s difference type, value type and iterator category, respectively.
So we can define our iterator trait to simply check for that:
template <class T, class = void>
struct is_iterator : std::false_type { };
template <class T>
struct is_iterator<T, void_t<
typename std::iterator_traits<T>::iterator_category
>> : std::true_type { };
If iterator_traits<T>::iterator_category is ill-formed, then T is not an iterator.
template<class T>
struct is_iterator
{
static T makeT();
typedef void * twoptrs[2]; // sizeof(twoptrs) > sizeof(void *)
static twoptrs & test(...); // Common case
template<class R> static typename R::iterator_category * test(R); // Iterator
template<class R> static void * test(R *); // Pointer
static const bool value = sizeof(test(makeT())) == sizeof(void *);
};
I believe this should be a complete solution. Try it on http://gcc.godbolt.org and see the resulting assembly for the test functions.
#include <type_traits>
#include <iterator>
#include <vector>
#include <utility>
template <typename T>
struct is_iterator {
static char test(...);
template <typename U,
typename=typename std::iterator_traits<U>::difference_type,
typename=typename std::iterator_traits<U>::pointer,
typename=typename std::iterator_traits<U>::reference,
typename=typename std::iterator_traits<U>::value_type,
typename=typename std::iterator_traits<U>::iterator_category
> static long test(U&&);
constexpr static bool value = std::is_same<decltype(test(std::declval<T>())),long>::value;
};
struct Foo {};
//Returns true
bool f() { return is_iterator<typename std::vector<int>::iterator>::value; }
//Returns true
bool fc() { return is_iterator<typename std::vector<int>::const_iterator>::value; }
//Returns true
bool fr() { return is_iterator<typename std::vector<int>::reverse_iterator>::value; }
//Returns true
bool fcr() { return is_iterator<typename std::vector<int>::const_reverse_iterator>::value; }
//Returns true
bool g() { return is_iterator<int*>::value; }
//Returns true
bool gc() { return is_iterator<const int*>::value; }
//Returns false
bool h() { return is_iterator<int>::value; }
//Returns false
bool i() { return is_iterator<Foo>::value; }
This implementation uses SFINAE and overloading precedence. test(U&&) always has higher precedence than test(...) so it will always be chosen if not removed by SFINAE.
For an iterator type T, std::iterator_traits<T> has all of the above mentioned typedefs present so test(U&&) and test(...) are both overload candidates. Since test(U&&) has higher precedence, its always chosen.
For a non-iterator type T, test(U&&) fails SFINAE because std::iterator_traits<T> does not have the nested typedefs. Therefore the only remaining candidate is test(...).
Note that this trait will also fail if someone specializes std::iterator_traits<T> for some type T and does not provide all of the required typedefs.
Well, you could check for the type to have a nested typedef called iterator_category This can be done using SFINAE, and the exact technique can be found in wiki page for SFINAE. This isn't a 100% method, but all decent iterators should provide the common typedefs for iterators, and the iterator_category is one that is unique to iterators. Also don't forget to check if TYPE is simply a pointer. Pointers are iterators.
I implemented this one some time ago:
template <typename T>
struct is_iterator {
template <typename U>
static char test(typename std::iterator_traits<U>::pointer* x);
template <typename U>
static long test(U* x);
static const bool value = sizeof(test<T>(nullptr)) == 1;
};
It compiles fine using your example. I can't test it on VC though.
Demo here.
The original poster clarified that they are actually asking for a way to identify an InputIterator (see http://en.cppreference.com/w/cpp/concept/InputIterator) because they want to be able to increment and dereference the iterator. This has a very simple SFINAE solution in standard C++11, e.g. similar to that from the gcc STL:
template<typename InputIterator>
using RequireInputIterator = typename
std::enable_if<std::is_convertible<typename
std::iterator_traits<InputIterator>::iterator_category,
std::input_iterator_tag>::value>::type;
...
// Example: declare a vector constructor from a pair of input iterators.
template <typename InputIterator, typename = RequireInputIterator<InputIterator> >
MyVector(InputIterator first, InputIterator last) { /* ... */ };
This relies on the iterator type traits classes, which define the typedefs that Armen Tsirunyan thought were required of the iterators themselves. (The iterators can provide those typedefs, but they can also provide them in traits classes, which is necessary in order to use naked pointers as iterators, and the standard library implementations are required to do so.)
Nothing new but a C++17 way of doing it :
#include <type_traits>
// default case
template <class T, class = void>
struct is_iterator : std::false_type
{
};
// specialization
template <class T>
struct is_iterator<T,
std::void_t<typename std::iterator_traits<T>::difference_type,
typename std::iterator_traits<T>::pointer,
typename std::iterator_traits<T>::reference,
typename std::iterator_traits<T>::value_type,
typename std::iterator_traits<T>::iterator_category>> : std::true_type
{
};
template <class T>
constexpr bool is_iterator_v = is_iterator<T>::value;
some tests:
#include <vector>
#include <list>
#include <map>
static_assert(is_iterator_v<std::vector<int>::iterator>);
static_assert(is_iterator_v<std::list<double>::const_iterator>);
static_assert(is_iterator_v<int*>);
static_assert(!is_iterator_v<std::list<double>>);
static_assert(!is_iterator_v<int>);
How it works:
Some background :
std::false_type::value == false
std::true_type::value == true
std::void_t<X> <=> void if X is a valid type. If not it will cause a substitution Failure
is_iterator<X> is seen as is_iterator<X, void>
If a specialization matches it will be used
Detail:
If T is an iterator then these types exist:
std::iterator_traits<T>::difference_type
std::iterator_traits<T>::pointer
std::iterator_traits<T>::reference
std::iterator_traits<T>::value_type
std::iterator_traits<T>::iterator_category
So std::void_t<...> is void.
The specialization match is_iterator<T,void> (and also is_iterator<T>) and inherit of std::true_type
If T is not an iterator then at least one of the previous type doesn't exist, so std::void_t<...> doesn't name a type and the whole specialization is an substitution Failure. So the only match for is_iterator is the default case whom inherit of std::false_type
template < class T, class Enabler = void >
struct is_iterator : public boost::false_type { };
template < class T >
struct is_iterator< T, typename boost::enable_if_c<
sizeof(*(*(T*)0)) + sizeof((*(T*)0)++) + sizeof(++(*(T*)0)) +
sizeof((*(T*)0) == (*(T*)0)) + sizeof((*(T*)0) != (*(T*)0)) +
sizeof((*(T*)0) = (*(T*)0)) >::type > : public boost::true_type { };
Since C++20:
The proper way to detect any iterator would be with concepts, namely, std::input_or_output_iterator.
Quoting cppreference:
template <class I>
concept input_or_output_iterator =
requires(I i) {
{ *i } -> /*can-reference*/;
} &&
std::weakly_incrementable<I>;
The input_or_output_iterator concept forms the basis of the iterator concept taxonomy; every iterator type satisfies the input_or_output_iterator requirements.
Note that the exposition only type /*can-reference*/ really just means not void, and can be accomplished like the following:
template <class T>
using with_ref_t = T &;
template <class T>
concept can_reference = requires() { typename detail::with_ref_t<T>; };

Specializing a template on a lambda in C++0x

I've written a traits class that lets me extract information about the arguments and type of a function or function object in C++0x (tested with gcc 4.5.0). The general case handles function objects:
template <typename F>
struct function_traits {
template <typename R, typename... A>
struct _internal { };
template <typename R, typename... A>
struct _internal<R (F::*)(A...)> {
// ...
};
typedef typename _internal<decltype(&F::operator())>::<<nested types go here>>;
};
Then I have a specialization for plain functions at global scope:
template <typename R, typename... A>
struct function_traits<R (*)(A...)> {
// ...
};
This works fine, I can pass a function into the template or a function object and it works properly:
template <typename F>
void foo(F f) {
typename function_traits<F>::whatever ...;
}
int f(int x) { ... }
foo(f);
What if, instead of passing a function or function object into foo, I want to pass a lambda expression?
foo([](int x) { ... });
The problem here is that neither specialization of function_traits<> applies. The C++0x draft says that the type of the expression is a "unique, unnamed, non-union class type". Demangling the result of calling typeid(...).name() on the expression gives me what appears to be gcc's internal naming convention for the lambda, main::{lambda(int)#1}, not something that syntactically represents a C++ typename.
In short, is there anything I can put into the template here:
template <typename R, typename... A>
struct function_traits<????> { ... }
that will allow this traits class to accept a lambda expression?
I think it is possible to specialize traits for lambdas and do pattern matching on the signature of the unnamed functor. Here is the code that works on g++ 4.5. Although it works, the pattern matching on lambda appears to be working contrary to the intuition. I've comments inline.
struct X
{
float operator () (float i) { return i*2; }
// If the following is enabled, program fails to compile
// mostly because of ambiguity reasons.
//double operator () (float i, double d) { return d*f; }
};
template <typename T>
struct function_traits // matches when T=X or T=lambda
// As expected, lambda creates a "unique, unnamed, non-union class type"
// so it matches here
{
// Here is what you are looking for. The type of the member operator()
// of the lambda is taken and mapped again on function_traits.
typedef typename function_traits<decltype(&T::operator())>::return_type return_type;
};
// matches for X::operator() but not of lambda::operator()
template <typename R, typename C, typename... A>
struct function_traits<R (C::*)(A...)>
{
typedef R return_type;
};
// I initially thought the above defined member function specialization of
// the trait will match lambdas::operator() because a lambda is a functor.
// It does not, however. Instead, it matches the one below.
// I wonder why? implementation defined?
template <typename R, typename... A>
struct function_traits<R (*)(A...)> // matches for lambda::operator()
{
typedef R return_type;
};
template <typename F>
typename function_traits<F>::return_type
foo(F f)
{
return f(10);
}
template <typename F>
typename function_traits<F>::return_type
bar(F f)
{
return f(5.0f, 100, 0.34);
}
int f(int x) { return x + x; }
int main(void)
{
foo(f);
foo(X());
bar([](float f, int l, double d){ return f+l+d; });
}
The void_t trick can help. How does `void_t` work?
Unless you have C++17, you'll need to include the definition of void_t:
template<typename... Ts> struct make_void { typedef void type;};
template<typename... Ts> using void_t = typename make_void<Ts...>::type;
Add an extra template argument to the original template, defaulted to void:
template <typename T, typename = void>
struct function_traits;
The traits object for simple functions is the same as you already have:
template <typename R, typename... A>
struct function_traits<R (*)(A...)>
{
using return_type = R;
using class_type = void;
using args_type = std:: tuple< A... >;
};
For non-const methods:
template <typename R, typename... A>
struct function_traits<R (C::*)(A...)>
{
using return_type = R;
using class_type = void;
using args_type = std:: tuple< A... >;
};
Don't forget const methods:
template <typename R, typename C, typename... A>
struct function_traits<R (C::*)(A...) const> // const
{
using return_type = R;
using class_type = C;
using args_type = std:: tuple< A... >;
};
Finally, the important trait. Given a class type, including lambda types, we want to forward from T to decltype(&T::operator()). We want to ensure that this trait is only available for types T for which ::operator() is available, and this is what void_t does for us. To enforce this constraint, we need to put &T::operator() into the trait signature somewhere, hence template <typename T> struct function_traits<T, void_t< decltype(&T::operator())
template <typename T>
struct function_traits<T, void_t< decltype(&T::operator()) > >
: public function_traits< decltype(&T::operator()) >
{
};
The operator() method in (non-mutable, non-generic) lambdas is const, which explains why we need the const template above.
But ultimately this is very restrictive. This won't work with generic lambdas, or objects with templated operator(). If you reconsider your design, you find find a different approach that is more flexible.
By delegating some of the work to a series of function templates instead of a class template, you can extract the relevant info.
First though, I should say that the relevant method is a const method, for a lambda (for a non-capturing, non-generic, non-mutable lambda). So you will not be able to tell the difference between a true lambda and this:
struct {
int operator() (int) const { return 7; }
} object_of_unnamed_name_and_with_suitable_method;
Therefore, I must assume that you don't want "special treatment" for lambdas, and you don't want to test if a type is a lambda type, and that instead you want to simply extract the return type, and the type of all arguments, for any object which is simple enough. By "simple enough" I mean, for example, that the operator() method is not itself a template. And, for bonus information, a boolean to tell us if an operator() method was present and used, as opposed to a plain old function.
// First, a convenient struct in which to store all the results:
template<bool is_method_, bool is_const_method_, typename C, typename R, typename ...Args>
struct function_traits_results {
constexpr static bool is_method = is_method_;
constexpr static bool is_const_method = is_const_method_;
typedef C class_type; // void for plain functions. Otherwise,
// the functor/lambda type
typedef R return_type;
typedef tuple<Args...> args_type_as_tuple;
};
// This will extract all the details from a method-signature:
template<typename>
struct intermediate_step;
template<typename R, typename C, typename ...Args>
struct intermediate_step<R (C::*) (Args...)> // non-const methods
: public function_traits_results<true, false, C, R, Args...>
{
};
template<typename R, typename C, typename ...Args>
struct intermediate_step<R (C::*) (Args...) const> // const methods
: public function_traits_results<true, true, C, R, Args...>
{
};
// These next two overloads do the initial task of separating
// plain function pointers for functors with ::operator()
template<typename R, typename ...Args>
function_traits_results<false, false, void, R, Args...>
function_traits_helper(R (*) (Args...) );
template<typename F, typename ..., typename MemberType = decltype(&F::operator()) >
intermediate_step<MemberType>
function_traits_helper(F);
// Finally, the actual `function_traits` struct, that delegates
// everything to the helper
template <typename T>
struct function_traits : public decltype(function_traits_helper( declval<T>() ) )
{
};