SFINAE resolution problems occur in CUDA but not in C++ - c++

I am trying to write a method hello() that is conditionally generated based on whether the some typename P can be constructed from P{Ptr<int>, Ptr<int>} using braces initializers, (where Ptr<int> wraps an int* and has a conversion operator to handle P{int*, int*}).
The below code works in C++ (https://godbolt.org/z/rMvzxbPWx), but not with NVCC, (https://godbolt.org/z/WGoP4aEK1).
#include <tuple>
#include <iostream>
#include <type_traits>
template<class U, typename... A>
constexpr decltype(void(U{ std::declval<A>()... }), std::true_type{}) is_braces_constructible_test(int) { return std::true_type{}; }
template<class U, typename... A>
constexpr std::false_type is_braces_constructible_test(...) { return std::false_type{}; }
template<typename U, typename Tu, typename = void>
struct is_braces_constructible { };
template<typename U, template<typename...> class Tu, typename ...A>
struct is_braces_constructible<U, Tu<A...>> {
constexpr static bool value = is_braces_constructible_test<U, A...>(0);
};
template<typename T>
struct Ptr {
T* ptr;
operator T* () { return ptr; }
};
struct Point {
int* x;
int* y;
};
template<typename U>
constexpr bool is_constructable_from_tuple() {
return is_braces_constructible<U, std::tuple<Ptr<int>, Ptr<int>>>::value;
}
template<typename P>
typename std::enable_if<is_constructable_from_tuple<P>(), void>::type hello()
{
std::cout << "P is constructible from std::tuple<Ptr<int>, Ptr<int>>" << std::endl;
}
int main() {
hello<Point>();
std::cout << is_constructable_from_tuple<Point>() << std::endl;
return 0;
}
But when I comment out the hello<Point>() line, the code compiles, and it outputs that is_constructable_from_tuple<Point>() == 1.
This strange, because is_constructable_from_tuple<Point>() is the condition that is used in the enable_if for the hello<Point>() method. It almost feels like at compile-time, is_constructable_from_tuple<Point>() evaluates to 0, but at runtime it evaluates to 1?
The code compiles if Point has the constructor Point(int*, int*){} but this is not required in C++.
I tried using specialization of classes instead of method specialization, and seems to work when the default/dummy-class has the same method signature. On my computer it prints "SFIANE WORKED".
(https://godbolt.org/z/Gv41ob8Gq)
template<typename U>
constexpr bool is_constructable_from_tuple() {
return is_braces_constructible<U, std::tuple<Ptr<int>, Ptr<int>>>::value;
}
template<typename P, typename = void>
struct Hello {
void hello() {
std::cout << "SFINAE ERROR" << std::endl;
}
};
template<typename P>
struct Hello<P, typename std::enable_if<is_constructable_from_tuple<P>()>::type> {
void hello() {
std::cout << "SFINAE WORKED" << std::endl;
}
};
int main() {
Hello<Point>().hello();
return 0;
}
But when I change it to this:
template<typename P, typename = void>
struct Hello {
};
template<typename P>
struct Hello<P, typename std::enable_if<is_constructable_from_tuple<P>()>::type> {
void hello() {
std::cout << "SFINAE WORKED" << std::endl;
}
};
It does not compile in NVCC (https://godbolt.org/z/68c3WY397), but compiles in C++ (https://godbolt.org/z/8hTEaEWad).
Additionally, on my computer, if I change the method in the specialized class to be ‘T hello()’, then it does not compile unless I also change the default class to ‘T hello()’, even though at runtime I can see from the console output that it’s returning a Point constructed from the specialized class and not the default class.
It seems like I can try returning std::declval() in the default SFINAE class that I'm not using.

Related

Could you please explain below code ? It compiles fine. Its related to check whether given class is base of another class [duplicate]

I want to get into more template meta-programming. I know that SFINAE stands for "substitution failure is not an error." But can someone show me a good use for SFINAE?
I like using SFINAE to check boolean conditions.
template<int I> void div(char(*)[I % 2 == 0] = 0) {
/* this is taken when I is even */
}
template<int I> void div(char(*)[I % 2 == 1] = 0) {
/* this is taken when I is odd */
}
It can be quite useful. For example, i used it to check whether an initializer list collected using operator comma is no longer than a fixed size
template<int N>
struct Vector {
template<int M>
Vector(MyInitList<M> const& i, char(*)[M <= N] = 0) { /* ... */ }
}
The list is only accepted when M is smaller than N, which means that the initializer list has not too many elements.
The syntax char(*)[C] means: Pointer to an array with element type char and size C. If C is false (0 here), then we get the invalid type char(*)[0], pointer to a zero sized array: SFINAE makes it so that the template will be ignored then.
Expressed with boost::enable_if, that looks like this
template<int N>
struct Vector {
template<int M>
Vector(MyInitList<M> const& i,
typename enable_if_c<(M <= N)>::type* = 0) { /* ... */ }
}
In practice, i often find the ability to check conditions a useful ability.
Heres one example (from here):
template<typename T>
class IsClassT {
private:
typedef char One;
typedef struct { char a[2]; } Two;
template<typename C> static One test(int C::*);
// Will be chosen if T is anything except a class.
template<typename C> static Two test(...);
public:
enum { Yes = sizeof(IsClassT<T>::test<T>(0)) == 1 };
enum { No = !Yes };
};
When IsClassT<int>::Yes is evaluated, 0 cannot be converted to int int::* because int is not a class, so it can't have a member pointer. If SFINAE didn't exist, then you would get a compiler error, something like '0 cannot be converted to member pointer for non-class type int'. Instead, it just uses the ... form which returns Two, and thus evaluates to false, int is not a class type.
In C++11 SFINAE tests have become much prettier. Here are a few examples of common uses:
Pick a function overload depending on traits
template<typename T>
std::enable_if_t<std::is_integral<T>::value> f(T t){
//integral version
}
template<typename T>
std::enable_if_t<std::is_floating_point<T>::value> f(T t){
//floating point version
}
Using a so called type sink idiom you can do pretty arbitrary tests on a type like checking if it has a member and if that member is of a certain type
//this goes in some header so you can use it everywhere
template<typename T>
struct TypeSink{
using Type = void;
};
template<typename T>
using TypeSinkT = typename TypeSink<T>::Type;
//use case
template<typename T, typename=void>
struct HasBarOfTypeInt : std::false_type{};
template<typename T>
struct HasBarOfTypeInt<T, TypeSinkT<decltype(std::declval<T&>().*(&T::bar))>> :
std::is_same<typename std::decay<decltype(std::declval<T&>().*(&T::bar))>::type,int>{};
struct S{
int bar;
};
struct K{
};
template<typename T, typename = TypeSinkT<decltype(&T::bar)>>
void print(T){
std::cout << "has bar" << std::endl;
}
void print(...){
std::cout << "no bar" << std::endl;
}
int main(){
print(S{});
print(K{});
std::cout << "bar is int: " << HasBarOfTypeInt<S>::value << std::endl;
}
Here is a live example: http://ideone.com/dHhyHE
I also recently wrote a whole section on SFINAE and tag dispatch in my blog (shameless plug but relevant) http://metaporky.blogspot.de/2014/08/part-7-static-dispatch-function.html
Note as of C++14 there is a std::void_t which is essentially the same as my TypeSink here.
Boost's enable_if library offers a nice clean interface for using SFINAE. One of my favorite usage examples is in the Boost.Iterator library. SFINAE is used to enable iterator type conversions.
Here's another (late) SFINAE example, based on Greg Rogers's answer:
template<typename T>
class IsClassT {
template<typename C> static bool test(int C::*) {return true;}
template<typename C> static bool test(...) {return false;}
public:
static bool value;
};
template<typename T>
bool IsClassT<T>::value=IsClassT<T>::test<T>(0);
In this way, you can check the value's value to see whether T is a class or not:
int main(void) {
std::cout << IsClassT<std::string>::value << std::endl; // true
std::cout << IsClassT<int>::value << std::endl; // false
return 0;
}
Examples provided by other answers seems to me more complicated than needed.
Here is the slightly easier to understand example from cppreference :
#include <iostream>
// this overload is always in the set of overloads
// ellipsis parameter has the lowest ranking for overload resolution
void test(...)
{
std::cout << "Catch-all overload called\n";
}
// this overload is added to the set of overloads if
// C is a reference-to-class type and F is a pointer to member function of C
template <class C, class F>
auto test(C c, F f) -> decltype((void)(c.*f)(), void())
{
std::cout << "Reference overload called\n";
}
// this overload is added to the set of overloads if
// C is a pointer-to-class type and F is a pointer to member function of C
template <class C, class F>
auto test(C c, F f) -> decltype((void)((c->*f)()), void())
{
std::cout << "Pointer overload called\n";
}
struct X { void f() {} };
int main(){
X x;
test( x, &X::f);
test(&x, &X::f);
test(42, 1337);
}
Output:
Reference overload called
Pointer overload called
Catch-all overload called
As you can see, in the third call of test, substitution fails without errors.
C++17 will probably provide a generic means to query for features. See N4502 for details, but as a self-contained example consider the following.
This part is the constant part, put it in a header.
// See http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2015/n4502.pdf.
template <typename...>
using void_t = void;
// Primary template handles all types not supporting the operation.
template <typename, template <typename> class, typename = void_t<>>
struct detect : std::false_type {};
// Specialization recognizes/validates only types supporting the archetype.
template <typename T, template <typename> class Op>
struct detect<T, Op, void_t<Op<T>>> : std::true_type {};
The following example, taken from N4502, shows the usage:
// Archetypal expression for assignment operation.
template <typename T>
using assign_t = decltype(std::declval<T&>() = std::declval<T const &>())
// Trait corresponding to that archetype.
template <typename T>
using is_assignable = detect<T, assign_t>;
Compared to the other implementations, this one is fairly simple: a reduced set of tools (void_t and detect) suffices. Besides, it was reported (see N4502) that it is measurably more efficient (compile-time and compiler memory consumption) than previous approaches.
Here is a live example, which includes portability tweaks for GCC pre 5.1.
Here is one good article of SFINAE: An introduction to C++'s SFINAE concept: compile-time introspection of a class member.
Summary it as following:
/*
The compiler will try this overload since it's less generic than the variadic.
T will be replace by int which gives us void f(const int& t, int::iterator* b = nullptr);
int doesn't have an iterator sub-type, but the compiler doesn't throw a bunch of errors.
It simply tries the next overload.
*/
template <typename T> void f(const T& t, typename T::iterator* it = nullptr) { }
// The sink-hole.
void f(...) { }
f(1); // Calls void f(...) { }
template<bool B, class T = void> // Default template version.
struct enable_if {}; // This struct doesn't define "type" and the substitution will fail if you try to access it.
template<class T> // A specialisation used if the expression is true.
struct enable_if<true, T> { typedef T type; }; // This struct do have a "type" and won't fail on access.
template <class T> typename enable_if<hasSerialize<T>::value, std::string>::type serialize(const T& obj)
{
return obj.serialize();
}
template <class T> typename enable_if<!hasSerialize<T>::value, std::string>::type serialize(const T& obj)
{
return to_string(obj);
}
declval is an utility that gives you a "fake reference" to an object of a type that couldn't be easily construct. declval is really handy for our SFINAE constructions.
struct Default {
int foo() const {return 1;}
};
struct NonDefault {
NonDefault(const NonDefault&) {}
int foo() const {return 1;}
};
int main()
{
decltype(Default().foo()) n1 = 1; // int n1
// decltype(NonDefault().foo()) n2 = n1; // error: no default constructor
decltype(std::declval<NonDefault>().foo()) n2 = n1; // int n2
std::cout << "n2 = " << n2 << '\n';
}
The following code uses SFINAE to let compiler select an overload based on whether a type has certain method or not:
#include <iostream>
template<typename T>
void do_something(const T& value, decltype(value.get_int()) = 0) {
std::cout << "Int: " << value.get_int() << std::endl;
}
template<typename T>
void do_something(const T& value, decltype(value.get_float()) = 0) {
std::cout << "Float: " << value.get_float() << std::endl;
}
struct FloatItem {
float get_float() const {
return 1.0f;
}
};
struct IntItem {
int get_int() const {
return -1;
}
};
struct UniversalItem : public IntItem, public FloatItem {};
int main() {
do_something(FloatItem{});
do_something(IntItem{});
// the following fails because template substitution
// leads to ambiguity
// do_something(UniversalItem{});
return 0;
}
Output:
Float: 1
Int: -1
Here, I am using template function overloading (not directly SFINAE) to determine whether a pointer is a function or member class pointer: (Is possible to fix the iostream cout/cerr member function pointers being printed as 1 or true?)
https://godbolt.org/z/c2NmzR
#include<iostream>
template<typename Return, typename... Args>
constexpr bool is_function_pointer(Return(*pointer)(Args...)) {
return true;
}
template<typename Return, typename ClassType, typename... Args>
constexpr bool is_function_pointer(Return(ClassType::*pointer)(Args...)) {
return true;
}
template<typename... Args>
constexpr bool is_function_pointer(Args...) {
return false;
}
struct test_debugger { void var() {} };
void fun_void_void(){};
void fun_void_double(double d){};
double fun_double_double(double d){return d;}
int main(void) {
int* var;
std::cout << std::boolalpha;
std::cout << "0. " << is_function_pointer(var) << std::endl;
std::cout << "1. " << is_function_pointer(fun_void_void) << std::endl;
std::cout << "2. " << is_function_pointer(fun_void_double) << std::endl;
std::cout << "3. " << is_function_pointer(fun_double_double) << std::endl;
std::cout << "4. " << is_function_pointer(&test_debugger::var) << std::endl;
return 0;
}
Prints
0. false
1. true
2. true
3. true
4. true
As the code is, it could (depending on the compiler "good" will) generate a run time call to a function which will return true or false. If you would like to force the is_function_pointer(var) to evaluate at compile type (no function calls performed at run time), you can use the constexpr variable trick:
constexpr bool ispointer = is_function_pointer(var);
std::cout << "ispointer " << ispointer << std::endl;
By the C++ standard, all constexpr variables are guaranteed to be evaluated at compile time (Computing length of a C string at compile time. Is this really a constexpr?).

How to specialise template method with type that itself is a template where only the return type relies on the template type?

I want to specialise a single template method in a non-template class to use an std::vector however only the return type of the method uses the template.
#include <iostream>
#include <string>
#include <vector>
class Foo
{
public:
template<typename T>
T Get()
{
std::cout << "generic" << std::endl;
return T();
}
};
template<>
int Foo::Get()
{
std::cout << "int" << std::endl;
return 12;
}
template<typename T>
std::vector<T> Foo::Get()
{
std::cout << "vector" << std::endl;
return std::vector<T>();
}
int main()
{
Foo foo;
auto s = foo.Get<std::string>();
auto i = foo.Get<int>();
}
This compiles with an error indicating that the std::vector attempted specialisation does not match any prototype of Foo, which is completely understandable.
In case it matters, use of C++14 is fine and dandy.
You can only partially specialize classes (structs) (cppreference) - so the way to overcome your problems is to add helper struct to allow this partial specialization of std::vector<T> - e.g. this way:
class Foo
{
private: // might be also protected or public, depending on your design
template<typename T>
struct GetImpl
{
T operator()()
{
std::cout << "generic" << std::endl;
return T();
}
};
public:
template<typename T>
auto Get()
{
return GetImpl<T>{}();
}
};
For int - you can fully specialize this function:
template<>
int Foo::GetImpl<int>::operator()()
{
std::cout << "int" << std::endl;
return 12;
}
For std::vector<T> you have to specialize entire struct:
template<typename T>
struct Foo::GetImpl<std::vector<T>>
{
std::vector<T> operator()()
{
std::cout << "vector" << std::endl;
return std::vector<T>();
}
};
Partial specialisation of template functions (including member functions) is not allowed. One option is to overload instead using SFINAE. For example,
/// auxiliary for is_std_vetor<> below
struct convertible_from_std::vector
{
template<typename T>
convertible_from_std::vector(std::vector<T> const&);
};
template<typename V>
using is_std_vector
= std::is_convertible<V,convertible_from_std_vector>;
class Foo
{
public:
template<typename T, std::enable_if_t< is_std::vector<T>::value,T>
Get()
{
std::cout << "vector" << std::endl;
return T();
}
template<typename T, std::enable_if_t<!is_std::vector<T>::value,T>
Get()
{
std::cout << "generic" << std::endl;
return T();
}
};
Note that the helper class is_std_vector may be useful in other contexts as well, so it worth having somewhere. Note further that you can make this helper class more versatile by asking for any std::vector or specific std::vector<specific_type, specific_allocator>. For example,
namespace traits {
struct Anytype {};
namespace details {
/// a class that is convertible form C<T,T>
/// if either T==AnyType, any type is possible
template<template<typename,typename> C, typename T1=Anytype,
typename T2=Anytype>
struct convCtTT
{
convCtTT(C<T1,T2> const&);
};
template<template<typename,typename> C, typename T1=Anytype>
struct convCtTT<C,T1,AnyType>
{
template<typename T2>
convCtTT(C<T1,T2> const&);
};
template<template<typename,typename> C, typename T2=Anytype>
struct convCtTT<C,AnyType,T2>
{
template<typename T1>
convCtTT(C<T1,T2> const&);
};
template<template<typename,typename> C>
struct convCtTT<C,AnyType,AnyType>
{
template<typename T1, typename T2>
convCtTT(C<T1,T2> const&);
};
}
template<typename Vector, typename ValueType=AnyType,
typename Allocator=AnyType>
using is_std_vector
= std::is_convertible<Vector,details::convCtTT<std::vector,ValueType,
Allocator>;
}
You can't partially specialze template in c++. You need to overload your function and pass the type in parameters.
#include <iostream>
#include <string>
#include <vector>
class Foo
{
public:
template<typename T>
T Get()
{
return this->getTemplate(static_cast<T*>(0)); //
}
private:
template<class T> T getTemplate(T* t)
{
std::cout << "generic" << std::endl;
return T();
}
template<class T> std::vector<T> getTemplate(std::vector<T>* t)
{
std::cout << "vector" << std::endl;
return std::vector<T>();
}
};
template <> int Foo::getTemplate(int* t)
{
std::cout << "int" << std::endl;
return 12;
}
int main()
{
Foo foo;
auto s = foo.Get<std::string>();
auto i = foo.Get<int>();
auto v = foo.Get<std::vector<int>>();
}
Edit : fixed a typo in the code

C++ Decltype for function template

I want to create an overloaded template, that runs a function Foo() if a class contains it, else it does nothing.
class A
{
public:
template <typename U>
void Foo(U& u)
{
std::cout << "Has Foo()" << std::endl;
// Modify u
}
};
class B
{
// Does not contain Foo()
};
I've been trying to run it as such
template <typename T, typename U>
decltype(std::declval<T>().Foo()) TriggerFoo(T* t, U& u)
{
t->Foo(u);
}
template <typename T, typename U>
void TriggerFoo(T* t, U& u)
{
std::cout << "Does not have Foo()" << std::endl;
}
int main()
{
A a;
B b;
U u; // Some type
TriggerFoo<A, U>(&a, u); // I want to print "Has Foo()".
TriggerFoo<B, U>(&b, u); // Prints "Does not have Foo()".
return 0;
}
At the moment, both classes are passed to the "Does not have Foo()" instantiation. It compiles, but obviously it doesn't work, and it is most probably because I don't understand declval well enough. I have also tried with non-template functions and it still does not work.
Any help will be greatly appreciated.
There were two basic issues with your approach:
decltype(std::declval<T>().Foo())
This will never be succesfully resolved, because the Foo() in question will always take a parameter. This part should be:
decltype(std::declval<T>().Foo(std::declval<U &>()))
But now you will run into a different problem: when the class implements Foo(), the template resolution will become ambiguous. Either template function can be used.
So, you need another level of indirection, and templates of different priorities:
#include <iostream>
#include <type_traits>
class A
{
public:
template <typename U>
void Foo(U& u)
{
std::cout << "Has Foo()" << std::endl;
// Modify u
}
};
class B
{
// Does not contain Foo()
};
template <typename T, typename U, typename Z=decltype(std::declval<T>().Foo(std::declval<U &>()))>
void DoTriggerFoo(T* t, U& u, int dummy)
{
t->Foo(u);
}
template <typename T, typename U>
void DoTriggerFoo(T* t, U& u, ...)
{
std::cout << "Does not have Foo()" << std::endl;
}
template <typename T, typename U>
void TriggerFoo(T *t, U &u)
{
DoTriggerFoo(t, u, 0);
}
class U {};
int main()
{
A a;
B b;
U u; // Some type
TriggerFoo<A, U>(&a, u); // I want to print "Has Foo()".
TriggerFoo<B, U>(&b, u); // Prints "Does not have Foo()".
return 0;
}
Results with gcc 5.3:
$ ./t
Has Foo()
Does not have Foo()
P.S.:
std::declval<T &>().Foo(std::declval<U &>())
It's possible that this will work better, with your actual classes.
Extension to Sam's answer, if you aren't using pointers you can simplify the code further which makes it look a bit neater.
#include <iostream>
#include <type_traits>
class A
{
public:
template <typename U>
void Foo(U& u)
{
std::cout << "Has Foo()\n";
}
};
class B
{
// Does not contain Foo()
};
template <
typename T,
typename U,
typename Z=decltype(std::declval<T>().Foo(std::declval<U&>()))>
void TriggerFoo(T& t, U& u)
{
t.Foo(u);
}
template <typename... T>
void TriggerFoo(const T&...)
{
std::cout << "Does not have Foo()\n";
}
class U {};
int main()
{
A a;
B b;
U u;
TriggerFoo<A, U>(a, u); // I want to print "Has Foo()".
TriggerFoo<B, U>(b, u); // Prints "Does not have Foo()".
return 0;
}

std::enable_if using its internal type and without using it

Why does it print "B"
#include <iostream>
template<typename T, typename U = void>
struct Test
{ static void apply() { std::cout << "A" << std::endl; } };
template<typename T>
struct Test<T, typename std::enable_if<true>::type>
{ static void apply() { std::cout << "B" << std::endl; } };
int main()
{
Test<int>::apply();
}
but this one "A"?:
#include <iostream>
template<typename T, typename U = void>
struct Test
{ static void apply() { std::cout << "A" << std::endl; } };
template<typename T>
struct Test<T, std::enable_if<true>>
{ static void apply() { std::cout << "B" << std::endl; } };
int main()
{
Test<int>::apply();
}
The only difference between them is that, in the first one, I'm using typename std::enable_it<true>::type as U (e.g, void), but in the second one, I'm directly using std::enable_if<true> as U, which is also a well defined type and with no more meaning as void.
Because when you write Test<int> you are actually writing Test<int, void> which will never be the same as Test<int, std::enable_if<true>> (though it is the same as Test<int, typename std::enable_if<true>::type>)
As typename std::enable_if<true>::type is the same type as void, the first snippet is equivalent to
template<typename T, typename U = void>
struct Test
{ static void apply() { std::cout << "A" << std::endl; } };
template<typename T>
struct Test<T, void> // since typename std::enable_if<true>::type == void
{ static void apply() { std::cout << "B" << std::endl; } };
Hence, the second definition is more specialized, therefore if you don't provide two template arguments, the latter wins in overload resolution.
However, in the second example, you it's just a specialization for the pair of types T and std::enable_if<true>, not for T and void.
This can be checked with std::is_same<std::enable_if<true>, void>, which evaluates to false (clearly, void doesn't have a type member type, so it can't be the same).
Hence for the second snippet, requesting T<int> will match with T<int, void> for which only one definition is relevant, namely the first one.

How do I determine if a type is callable with only const references?

I want to write a C++ metafunction is_callable<F, Arg> that defines value to be true, if and only if the type F has the function call operator of the form SomeReturnType operator()(const Arg &). For example, in the following case
struct foo {
void operator(const int &) {}
};
I want is_callable<foo, int &> to be false and is_callable<foo, const int &> to be true. This is what I have so far :
#include <memory>
#include <iostream>
template<typename F, typename Arg>
struct is_callable {
private:
template<typename>
static char (&test(...))[2];
template<unsigned>
struct helper {
typedef void *type;
};
template<typename UVisitor>
static char test(
typename helper<
sizeof(std::declval<UVisitor>()(std::declval<Arg>()), 0)
>::type
);
public:
static const bool value = (sizeof(test<F>(0)) == sizeof(char));
};
struct foo {
void operator()(const int &) {}
};
using namespace std;
int main(void)
{
cout << is_callable<foo, int &>::value << "\n";
cout << is_callable<foo, const int &>::value << "\n";
return 0;
}
This prints 1 and 1, but I want 0 and 1 because foo only defines void operator()(const int &).
After hours of playing around and some serious discussions in the C++ chat room, we finally got a version that works for functors with possibly overloaded or inherited operator() and for function pointers, based on #KerrekSB's and #BenVoigt's versions.
#include <utility>
#include <type_traits>
template <typename F, typename... Args>
class Callable{
static int tester[1];
typedef char yes;
typedef yes (&no)[2];
template <typename G, typename... Brgs, typename C>
static typename std::enable_if<!std::is_same<G,C>::value, char>::type
sfinae(decltype(std::declval<G>()(std::declval<Brgs>()...)) (C::*pfn)(Brgs...));
template <typename G, typename... Brgs, typename C>
static typename std::enable_if<!std::is_same<G,C>::value, char>::type
sfinae(decltype(std::declval<G>()(std::declval<Brgs>()...)) (C::*pfn)(Brgs...) const);
template <typename G, typename... Brgs>
static char sfinae(decltype(std::declval<G>()(std::declval<Brgs>()...)) (G::*pfn)(Brgs...));
template <typename G, typename... Brgs>
static char sfinae(decltype(std::declval<G>()(std::declval<Brgs>()...)) (G::*pfn)(Brgs...) const);
template <typename G, typename... Brgs>
static yes test(int (&a)[sizeof(sfinae<G,Brgs...>(&G::operator()))]);
template <typename G, typename... Brgs>
static no test(...);
public:
static bool const value = sizeof(test<F, Args...>(tester)) == sizeof(yes);
};
template<class R, class... Args>
struct Helper{ R operator()(Args...); };
template<typename R, typename... FArgs, typename... Args>
class Callable<R(*)(FArgs...), Args...>
: public Callable<Helper<R, FArgs...>, Args...>{};
Live example on Ideone. Note that the two failing tests are overloaded operator() tests. This is a GCC bug with variadic templates, already fixed in GCC 4.7. Clang 3.1 also reports all tests as passed.
If you want operator() with default arguments to fail, there is a possible way to do that, however some other tests will start failing at that point and I found it as too much hassle to try and correct that.
Edit: As #Johannes correctly notes in the comment, we got a little inconsistency in here, namely that functors which define a conversion to function pointer will not be detected as "callable". This is, imho, pretty non-trivial to fix, as such I won't bother with it (for now). If you absolutely need this trait, well, leave a comment and I'll see what I can do.
Now that all this has been said, IMHO, the idea for this trait is stupid. Why whould you have such exact requirements? Why would the standard is_callable not suffice?
(Yes, I think the idea is stupid. Yes, I still went and built this. Yes, it was fun, very much so. No, I'm not insane. Atleast that's what I believe...)
(with apologies to Kerrek for using his answer as a starting point)
EDIT: Updated to handle types without any operator() at all.
#include <utility>
template <typename F, typename Arg>
struct Callable
{
private:
static int tester[1];
typedef char yes;
typedef struct { char array[2]; } no;
template <typename G, typename Brg>
static char sfinae(decltype(std::declval<G>()(std::declval<Brg>())) (G::*pfn)(Brg)) { return 0; }
template <typename G, typename Brg>
static char sfinae(decltype(std::declval<G>()(std::declval<Brg>())) (G::*pfn)(Brg) const) { return 0; }
template <typename G, typename Brg>
static yes test(int (&a)[sizeof(sfinae<G,Brg>(&G::operator()))]);
template <typename G, typename Brg>
static no test(...);
public:
static bool const value = sizeof(test<F, Arg>(tester)) == sizeof(yes);
};
struct Foo
{
int operator()(int &) { return 1; }
};
struct Bar
{
int operator()(int const &) { return 2; }
};
struct Wazz
{
int operator()(int const &) const { return 3; }
};
struct Frob
{
int operator()(int &) { return 4; }
int operator()(int const &) const { return 5; }
};
struct Blip
{
template<typename T>
int operator()(T) { return 6; }
};
struct Boom
{
};
struct Zap
{
int operator()(int) { return 42; }
};
#include <iostream>
int main()
{
std::cout << "Foo(const int &): " << Callable<Foo, int const &>::value << std::endl
<< "Foo(int &): " << Callable<Foo, int &>::value << std::endl
<< "Bar(const int &): " << Callable<Bar, const int &>::value << std::endl
<< "Bar(int &): " << Callable<Bar, int &>::value << std::endl
<< "Zap(const int &): " << Callable<Zap , const int &>::value << std::endl
<< "Zap(int&): " << Callable<Zap , int &>::value << std::endl
<< "Wazz(const int &): " << Callable<Wazz, const int &>::value << std::endl
<< "Wazz(int &): " << Callable<Wazz, int &>::value << std::endl
<< "Frob(const int &): " << Callable<Frob, const int &>::value << std::endl
<< "Frob(int &): " << Callable<Frob, int &>::value << std::endl
<< "Blip(const int &): " << Callable<Blip, const int &>::value << std::endl
<< "Blip(int &): " << Callable<Blip, int &>::value << std::endl
<< "Boom(const int &): " << Callable<Boom, const int &>::value << std::endl
<< "Boom(int&): " << Callable<Boom, int &>::value << std::endl;
}
Demo: http://ideone.com/T3Iry
Here's something I hacked up which may or may not be what you need; it does seem to give true (false) for (const) int &...
#include <utility>
template <typename F, typename Arg>
struct Callable
{
private:
typedef char yes;
typedef struct { char array[2]; } no;
template <typename G, typename Brg>
static yes test(decltype(std::declval<G>()(std::declval<Brg>())) *);
template <typename G, typename Brg>
static no test(...);
public:
static bool const value = sizeof(test<F, Arg>(nullptr)) == sizeof(yes);
};
struct Foo
{
int operator()(int &) { return 1; }
// int operator()(int const &) const { return 2; } // enable and compare
};
#include <iostream>
int main()
{
std::cout << "Foo(const int &): " << Callable<Foo, int const &>::value << std::endl
<< "Foo(int &): " << Callable<Foo, int &>::value << std::endl
;
}
Something like this maybe? It's a bit round about to make it work on VS2010.
template<typename FPtr>
struct function_traits_impl;
template<typename R, typename A1>
struct function_traits_impl<R (*)(A1)>
{
typedef A1 arg1_type;
};
template<typename R, typename C, typename A1>
struct function_traits_impl<R (C::*)(A1)>
{
typedef A1 arg1_type;
};
template<typename R, typename C, typename A1>
struct function_traits_impl<R (C::*)(A1) const>
{
typedef A1 arg1_type;
};
template<typename T>
typename function_traits_impl<T>::arg1_type arg1_type_helper(T);
template<typename F>
struct function_traits
{
typedef decltype(arg1_type_helper(&F::operator())) arg1_type;
};
template<typename F, typename Arg>
struct is_callable : public std::is_same<typename function_traits<F>::arg1_type, const Arg&>
{
}
Here is a possible solution that utilizes an extra test to see if your template is being instantiated with a const T&:
#include <memory>
#include <iostream>
using namespace std;
template<typename F, typename Arg>
struct is_callable {
private:
template<typename>
static char (&test(...))[2];
template<bool, unsigned value>
struct helper {};
template<unsigned value>
struct helper<true, value> {
typedef void *type;
};
template<typename T>
struct is_const_ref {};
template<typename T>
struct is_const_ref<T&> {
static const bool value = false;
};
template<typename T>
struct is_const_ref<const T&> {
static const bool value = true;
};
template<typename UVisitor>
static char test(typename helper<is_const_ref<Arg>::value,
sizeof(std::declval<UVisitor>()(std::declval<Arg>()), 0)>::type);
public:
static const bool value = (sizeof(test<F>(0)) == sizeof(char));
};
struct foo {
void operator()(const int &) {}
};
int main(void)
{
cout << is_callable<foo, int &>::value << "\n";
cout << is_callable<foo, const int &>::value << "\n";
return 0;
}
Ran across this while doing something else, was able to adapt my code to fit. It has the same features (and limitations) as #Xeo, but does not need sizeof trick/enable_if. The default parameter takes the place of needing to do the enable_if to handle template functions. I tested it under g++ 4.7 and clang 3.2 using the same test code Xeo wrote up
#include <type_traits>
#include <functional>
namespace detail {
template<typename T, class Args, class Enable=void>
struct call_exact : std::false_type {};
template<class...Args> struct ARGS { typedef void type; };
template<class T, class ... Args, class C=T>
C * opclass(decltype(std::declval<T>()(std::declval<Args>()...)) (C::*)(Args...)) { }
template<class T, class ... Args, class C=T>
C * opclass(decltype(std::declval<T>()(std::declval<Args>()...)) (C::*)(Args...) const) { }
template<typename T, class ... Args>
struct call_exact<T, ARGS<Args...>,
typename ARGS<
decltype(std::declval<T&>()(std::declval<Args>()...)),
decltype(opclass<T, Args...>(&T::operator()))
>::type
> : std::true_type {};
}
template<class T, class ... Args>
struct Callable : detail::call_exact<T, detail::ARGS<Args...>> { };
template<typename R, typename... FArgs, typename... Args>
struct Callable<R(*)(FArgs...), Args...>
: Callable<std::function<R(FArgs...)>, Args...>{};