I'm trying to build a trait that checks for the existence of a nested, templated class. This is my take for checking whether a class O has a nested class inner with template parameter T:
template <typename O, typename T> struct has_inner {
static const bool value = std::is_class<typename O::template inner<T> >::value;
};
However, this does not work properly. Given two example classes dummy and ok
struct dummy {};
struct ok {
template <typename T>
struct inner {
};
};
The check on ok
std::cout << std::boolalpha << has_inner<ok, float>::value << std::endl;
will work, whereas the check on dummy
std::cout << std::boolalpha << has_inner<dummy, int>::value << std::endl;
will fail to compile on clang 3.2 with the error
error: 'inner' following the 'template' keyword does not refer to a template
static const bool value = std::is_class<typename O::template inner<T> >::value;
^~~~~
note: in instantiation of template class 'has_inner<dummy, int>' requested here
std::cout << std::boolalpha << has_inner<dummy, int>::value << std::endl;
It appears that the compiler tries to actually form that templated expression prior to passing it on to std::is_class. Consequently I see two solutions:
Tell the compiler to delay the template expansion, or
Use a different approach altogether.
However, I don't know how to perform either, can anyone help?
THE PROBLEM
You normally implement traits like this using, and relying on, SFINAE, something which your implementation doesn't take advantage of.
As stated the compiler will try to instantiate typename O::template inner<T>, no matter if it's possible or not; and if it isn't possible the compiler will throw an error diagnostic in your face.
What you need to do is a conditional check to see if T actually has a template-class inside it, without instantiating it if it hasn't.
THE SOLUTION - SFINAE TO THE RESCUE!
An implementation might look like the below snippet, an explanation will follow.
namespace impl {
template<class T, class... Args>
struct has_inner {
template<class U, typename = typename U::template inner<Args...>> // (A)
static std::true_type test (int);
template<class U>
static std::false_type test (...); // (B)
using result_type = decltype (test<T> (0)); // (C)
};
}
template<class... Ts>
using has_inner = typename impl::has_inner<Ts...>::result_type;
Note: by using decltype(test<T>(0)) we will have either std::true_type, or std::false_type which are both the standard behavior when dealing with results from type-traits.
The rules of SFINAE states that if a function template would yield an invalid function declaration upon instantiation, it is as if this function didn't exist, the compiler will try searching for another match, instead of giving up.
This is what happens at (C), we try to call (A) but if that fails (ie. an invalid expression is yield inside template<class U, typename ...> we will end up calling (B).
(B) isn't as good match as a successful instantiation of (A), but if (A) can't be instantiated.. (B) will do.
You need to use a trait class and SFINAE, something like this:
template<class A, typename B>
struct has_inner
{
private:
template<class T, typename U>
static std::true_type has(typename T::template inner<U>*);
template<class, typename>
static std::false_type has(...);
public:
static constexpr auto value = decltype(has<A, B>(nullptr))::value;
};
Now you can use it with correct results:
static_assert(has_inner<ok, float>::value, "ok does not have inner"); // OK
static_assert(has_inner<dummy, float>::value, "dummy does not have inner"); // ERROR
Related
Since C++20 concepts aren't standardized yet, I'm using static_assert as a makeshift concept check, to provide helpful error messages if a type requirement isn't met. In this particular case, I have a function which requires that a type is callable before getting its result type:
template <typename F, typename... Args>
void example() {
static_assert(std::is_invocable_v<F, Args...>, "Function must be callable");
using R = std::invoke_result_t<F, Args...>;
// ...
}
In addition, I require that the callable's result must be some kind of std::optional, but I don't know what type the optional will hold, so I need to get that type from it:
using R = // ...
using T = typename R::value_type; // std::optional defines a value_type
However, this will fail if type R doesn't have a value_type, e.g. if it's not a std::optional as expected. I'd like to have a static_assert to check for that first, with another nice error message if the assertion fails.
I could check for an exact type with something like std::is_same_v, but in this case I don't know the exact type. I want to check that R is some instance of std::optional, without specifying which instance it must be.
One way to do that is with a helper trait:
template <typename T>
struct is_optional { static constexpr bool value = false; };
template <typename T>
struct is_optional<std::optional<T>> { static constexpr bool value = true; };
template <typename T>
constexpr bool is_optional_v = is_optional<T>::value;
…and then I can write:
static_assert(is_optional_v<R>, "Function's result must be an optional");
That works, but it seems a little awkward to pollute my namespace with a helper trait just for a one-off check like this. I don't expect to need is_optional anywhere else, though I can imagine possibly ending up with other one-off traits like is_variant or is_pair too.
So I'm wondering: is there a more concise way to do this? Can I do the pattern matching on instances of std::optional without having to define the is_optional trait and its partial specialization?
Following the suggestion by several respondents, I made a re-usable trait:
template <typename T, template <typename...> typename Tpl>
struct is_template_instance : std::false_type { };
template <template <typename...> typename Tpl, typename... Args>
struct is_template_instance<Tpl<Args...>, Tpl> : std::true_type { };
template <typename T, template <typename...> typename Tpl>
constexpr bool is_template_instance_v = is_template_instance<T, Tpl>::value;
…so that I can write:
static_assert(is_template_instance_v<R, std::optional>, "Function's result must be an optional");
This is just as many lines and declarations as the is_optional trait, but it's no longer a one-off; I can use the same trait for checking other kinds of templates (like variants and pairs). So now it feels like a useful addition to my project instead of a kluge.
Can I do the pattern matching on instances of std::optional without having to define the is_optional trait and its partial specialization?
Maybe using implicit deduction guides for std::optional?
I mean... something as
using S = decltype(std::optional{std::declval<R>()});
static_assert( std::is_same_v<R, S>, "R isn't a std::optional" );
Explanation.
When R is std::optional<T> for some T type, std::optional{r} (for an r value of type R) should call the copy constructor and the resulting value should be of the same type R.
Otherwise, the type should be different (std::optional<R>).
The following is a full compiling example.
#include <iostream>
#include <optional>
template <typename T>
bool isOptional ()
{
using U = decltype(std::optional{std::declval<T>()});
return std::is_same_v<T, U>;
}
int main ()
{
std::cout << isOptional<int>() << std::endl; // print 0
std::cout << isOptional<std::optional<int>>() << std::endl; // print 1
}
Anyway, I support the suggestion by super: create a more generic type-traits that receive std::option as template-template argument.
I'm trying to combine the approaches used in this answer for detecting whether a class has a member variable x with this answer to select different implementations depending on that using enable_if.
Basically, I want to write a trait class that, given a type T, provides access to the member T::x if it exists, and provides a default value otherwise.
The following code does not compile on g++: (Compiler Explorer)
#include <iostream>
#include <type_traits>
// classes with / without x member
struct WithX { static constexpr int x = 42; };
struct WithoutX {};
// trait to detect x
template <typename T, typename = void>
struct HasX : std::false_type { };
template <typename T>
struct HasX <T, decltype((void) T::x)> : std::true_type { };
// trait to provide default for x
template <typename T>
struct FooTraits
{
template <bool enable = HasX<T>::value>
static constexpr std::enable_if_t< enable, size_t> x() { return T::x; }
template <bool enable = HasX<T>::value>
static constexpr std::enable_if_t<!enable, size_t> x() { return 1; }
};
int main() {
std::cout << HasX<WithX>::value << std::endl;
// Uncomment the following line to make this compile with g++
//std::cout << HasX<WithoutX>::value << std::endl;
std::cout << FooTraits<WithoutX>::x() << std::endl;
}
g++ gives error messages that
error: 'x' is not a member of 'WithoutX'
struct HasX <T, decltype((void) T::x)> : std::true_type { };
in the part which should detect whether x is a member in the first place. Curiously though, if I uncomment the second to last line which instantiates HasX<WithoutX>::value by itself, g++ compiles without errors (Compiler Explorer).
Both clang and msvc compile without a problem on Compiler Explorer.
What's wrong here?
SFINAE only work in immediate context. In other words, if the compiler can see in advance that a declaration has a problem, then it must be an error.
When instantiating a class, the compiler will try to resolve everything it can. So is this:
template<bool enable = HasX<T>::value>
....
This is not dependent of the context of the function. This can be instantiated right when FooTraits is instantiated.
In other words, this assignation can be calculated in advance, as if you'd move it to the class scope.
In your case, the compiler has nothing to do at subtitution.
The fix is simply that:
template <typename U = T, bool enable = HasX<U>::value>
static constexpr std::enable_if_t< enable, size_t> x() { return T::x; }
template <typename U = T, bool enable = HasX<U>::value>
static constexpr std::enable_if_t<!enable, size_t> x() { return 1; }
In theory, U could be a completely different type. U is immediate to the function instantiation, while T is not.
Fact that switching comment of:
//std::cout << HasX<WithoutX>::value << std::endl;
is indeed a good sign of gcc bug.
Seems gcc has issue with your form:
template <typename T>
struct HasX <T, decltype((void) T::x)> : std::true_type {};
A more typical way is to use std::void_t:
template <typename T>
struct HasX <T, std::void_t<decltype(T::x)>> : std::true_type {};
which indeed solves the issue Demo.
This code works:
// Code A
#include <iostream>
#include <vector>
#include <type_traits>
using namespace std;
template <typename T>
struct S {
template <typename Iter, typename = typename enable_if<is_constructible<T, decltype(*(declval<Iter>()))>::value>::type>
S(Iter) { cout << "S(Iter)" << endl; }
S(int) { cout << "S(int)" << endl; }
};
int main()
{
vector<int> v;
S<int> s1(v.begin()); // stdout: S(Iter)
S<int> s2(1); // stdout: S(int)
}
But this code below doesn't work. In the code below, I merely want to inherit std::enable_if, so the class is_iter_of will have member typedef type if the selected version of std::enable_if has member typedef type.
// Code B
#include <iostream>
#include <vector>
#include <type_traits>
using namespace std;
template <typename Iter, typename Target>
struct is_iter_of : public enable_if<is_constructible<Target, decltype(*(declval<Iter>()))>::value> {}
template <typename T>
struct S {
template <typename Iter, typename = typename is_iter_of<Iter, T>::type>
S(Iter) { cout << "S(Iter)" << endl; }
S(int) { cout << "S(int)" << endl; }
};
int main()
{
vector<int> v;
S<int> s1(v.begin());
S<int> s2(1); // this is line 22, error
}
Error message:
In instantiation of 'struct is_iter_of<int, int>':
12:30: required by substitution of 'template<class Iter, class> S<T>::S(Iter) [with Iter = int; <template-parameter-1-2> = <missing>]'
22:16: required from here
8:72: error: invalid type argument of unary '*' (have 'int')
The error message is bewildering: of course I want the template substitution to fail.. so the correct constructor could be selected. Why didn't SFINAE work in Code B? If invalid type argument of unary '*' (have 'int') offends the compiler, the compiler should have issued a same error for Code A as well.
The problem is that the expression *int (*(declval<Iter>())) is invalid, so your template fails. You need to another level of templating, so I suggest a void_t approach:
make is_iter_of by a concept-lite that derives from true_type or fals_type
use enable_if within the definition of your class to enable the iterator constructor.
The key thing to understand is that your constructor before needed a type for typename is_iter_of<Iter, T>::type except that your enable_if in the struct is_iter_of caused the entire thing to be ill-formed. And since there was no fall-back template you had a compiler error.
template<class...>
using voider = void;
template <typename Iter, typename Target, typename = void>
struct is_iter_of : std::false_type{};
template <typename Iter, typename Target>
struct is_iter_of<Iter, Target, voider<decltype(*(declval<Iter>()))>> : std::is_constructible<Target, decltype(*(declval<Iter>()))> {};
template <typename T>
struct S {
template <typename Iter, typename std::enable_if<is_iter_of<Iter, T>::value, int>::type = 0>
S(Iter) { cout << "S(Iter)" << endl; }
S(int) { cout << "S(int)" << endl; }
};
Demo (C++11)
What's happening
The additional voider makes the template specialization not preferred if *(declval<Iter>()) is an ill-formed expression (*int) and so the fallback base template (std::false_type) is chosen.
Else, it will derived from std::is_constructible``. In other words, it can still derive fromstd::false_typeif the expression is well-formed but it's not constructibe, andtrue_type` otherwise.
The thing is you're trying to extend from std::enable_if, but the expression you put inside the enable if may be invalid. Since you are using a class that inherit form that, the class you instanciate inherit from an invalid expression, hence the error.
An easy solution for having a name for your enable_if expression would be to use an alias instead of a class:
template <typename Iter, typename Target>
using is_iter_of = enable_if<is_constructible<Target, decltype(*(declval<Iter>()))>::value>;
SFINAE will still work as expected with an alias.
This is because instancing an alias is part of the function you try to apply SFINAE on. With inheritance, the expression is part of the class being instanciated, not the function. This is why you got a hard error.
The thing is, the is multiple ways SFINAE is applied in your case. Let's take a look at where SFINAE can happen:
enable_if< // here -------v
is_constructible<Target, decltype(*(declval<Iter>()))>::value
>::type
// ^--- here
Indeed, SFINAE will happen because enable_if::type will not exist if the bool parameter is false, causing SFINAE.
But if you look closely, another type might not exist: decltype(*(std::declval<Iter>())). If Iter is int, asking for the type of the star operator makes no sense. So SFINAE if applied there too.
Your solution with inheritance would have work if every class you send as Iter had the * operator available. Since with int it does not exist, you are sending a non existing type to std::is_constructible, making the whole expression forming the base class invalid.
With the alias, the whole expression of using std::enable_if is subject to apply SFINAE. Whereas the base class approach will only apply SFINAE on the result of std::enable_if.
It is easy to use SFINAE to hide a particular function overload if a particular expression is not well-formed. But I want to do the opposite, hiding an overload if and only if a given expression is well-formed, and to do so in a very general way. I have a solution that's working in clang 3.5.0 and gcc 5.2.0, but I'm interested in any comments and alternatives.
Ideally, there would be a builtin constexpr bool function/macro that would tell us at compile time whether a particular expression is well formed.
IS_WELL_FORMED( declval<T>() < declval<T>() ) // I want this as bool
which could be used with enable_if to enable or disable overloads.
I have found a solution, but I have come across some strange behaviour in g++ 5.2.0 and clang 3.5.0 and I wonder if either are buggy.
A proposed solution
First, the most robust solution I've found so far, which works on both compilers. For example, I want to test if T has a .length() method. This requires "hiding" the expression inside another template. Also, a function called well_formed_default that I'll discuss later.
// Define a template to contain our expression
template<typename T2=T, typename =
decltype( declval<T2>().length() ) // This line is the expression to test
> struct test_for_length_method { };
and here is how it might be used in a containing class:
template<typename T>
struct Demo { // the main struct I'm working on
// Define a template to "hide" our expression
template<typename T2=T, typename =
decltype( declval<T2>().length() ) // This line is the expression to test
> struct test_for_length_method { };
// test if the above "test" succeeds
constexpr bool T_has_length =
well_formed_default< test_for_length_method >();
// demonstrate the bool in an enable_if
template<bool b = T_has_length>
static
auto demo_enable_if() -> typename std::enable_if< b >::type {
cout << "T has length" << endl;
}
template<bool b = T_has_length>
static
auto demo_enable_if() -> typename std::enable_if< !b >::type {
cout << "T doesn't" << endl;
}
}
The above works as expected with Demo<int>::demo_enable_if() and Demo<std::string>::demo_enable_if().
I can't use T_has_length directly inside the enable_if as it will lead to hard errors because it's not template substitution. Therefore, I pretend it is a template parameter by making a copy of if in another template parameter bool b = T_has_length. This is similar to how we have to use typename T2=T inside the test struct. A bit annoying, but I guess it makes sense.
I now define well_formed_default. It takes a template (and optionally some types) and returns true or false depending on whether it can construct the template with those particular args. I would include it automatically in all my projects. Perhaps something like this already exists in the standard?
template<template<class...> class Template, class ...Args>
constexpr auto well_formed_default_impl(int)
-> typename std::conditional<false,Template<Args...>, bool>::type {
return true;
}
template<template<class...> class Template, class ...Args>
constexpr auto well_formed_default_impl(...)
-> bool {
return false;
}
template<template<class...> class Template, class ...Args>
constexpr bool well_formed_default() {
return well_formed_default_impl<Template,Args...>(0);
}
--
My (first) question
This works in both g++ 5.2.0 and clang 3.5.0. But should it? Is this fully standard, or am I pushing the standard too far? I guess the weirdest thing for me is the use of Template<Args...> inside well_formed_default_impl - is this guaranteed to be a substitution failure in the way I use it? e.g. with test_for_pushback_method_struct<> when the relevant decltype isn't well-formed?
--
Why can't I use an alias instead?
(For the remainder of this question, it might help to look at the output of this code on Coliru as it has all the tests and results I'm discussing below.)
I began this project with an alias instead of the above struct. I thought it would be equivalent. But instead, with both compilers, they think that string does not have a length method.
template<typename T2=T>
using test_for_length_method_alias = decltype( declval<T2>().length() );
Finally, I tried both the struct and the alias, but where I explicitly define the first type parameter (T) instead of relying on the the default T2=T. This shouldn't change anything, because I'm passing the type that is the default - but it does change the behaviour! Using the struct with an explicit first parameter
well_formed_default<test_for_length_method_struct , T>
works correctly on both compilers. But the alias-with-explicit-first-type only works correctly with clang:
well_formed_default<test_for_length_method_alias , T>
Here is can_apply boilerplate:
template<class...>struct voider{using type=void;};
template<class...Ts>using void_t=typename voider<Ts...>::type;
namespace details {
template<template<class...>class Z, class, class...>
struct can_apply:std::false_type{};
template<template<class...>class Z, class...Ts>
struct can_apply<Z, void_t<Z<Ts...>>, Ts...>:
std::true_type{};
}
template<template<class...>class Z, class...Ts>
using can_apply=details::can_apply<Z, void, Ts...>;
For the particular problem if x<y using it looks like:
template<class Lhs, class Rhs>
using less_r = decltype( std::declval<Lhs>() < std::declval<Rhs>() );
template<class Lhs, class Rhs>
using can_less = can_apply< less_r, Lhs, Rhs >;
And then using can_less:
struct Foo {};
struct Bar {};
void operator<( Foo, Bar ) {}
int main() {
std::cout << can_less<Foo, Bar>{} << can_less<Bar,Foo>{} << can_less<int, int>{} << can_less<char*, int>{} << '\n';
}
output is 1010 in both clang and gcc.
This works under the standard, and it matches roughly the interface of a std::experimental::is_detected (with fewer features, but simpler to implement).
It's somewhat unlikely that there will be any changes to the language to support this sort of uses directly (except what concepts will bring). Concepts will make it easier to write mutually exclusive overloads and negated concepts allow writing overloads
that are enabled if an expression is not well-formed. (And yes, I know that that doesn't help you write such code for C++11 or C++14.) Example:
#include <iostream>
template <class T>
requires !requires(T t) {t.f();}
void f()
{
std::cout << "does not support f()!" << std::endl;
}
template <class T>
void f()
{
std::cout << "supports f()!" << std::endl;
}
struct A {};
struct B {void f() {}};
int main()
{
f<A>();
f<B>();
}
I added the unconstrained overload just for illustration purposes.
Leaving it out would make the call f<B>() ill-formed. The code works today on gcc trunk, and you can try it out on melpon.org/wandbox.
I have the following snipped of code, which does not compile.
#include <iostream>
struct A {
void foo() {}
};
struct B : public A {
using A::foo;
};
template<typename U, U> struct helper{};
int main() {
helper<void (A::*)(), &A::foo> compiles;
helper<void (B::*)(), &B::foo> does_not_compile;
return 0;
}
It does not compile since &B::foo resolves to &A::foo, and thus it cannot match the proposed type void (B::*)(). Since this is part of a SFINAE template that I am using to check for a very specific interface (I'm forcing specific argument types and output types), I would like for this to work independently of inheritances, while keeping the check readable.
What I tried includes:
Casting the second part of the argument:
helper<void (B::*)(), (void (B::*)())&B::foo> does_not_compile;
This unfortunately does not help as the second part is now not recognized as a constant expression, and fails.
I've tried assigning the reference to a variable, in order to check that.
constexpr void (B::* p)() = &B::foo;
helper<void (B::* const)(), p> half_compiles;
This code is accepted by clang 3.4, but g++ 4.8.1 rejects it, and I have no idea on who's right.
Any ideas?
EDIT: Since many comments are asking for a more specific version of the problem, I'll write it here:
What I'm looking for is a way to explicitly check that a class respects a specific interface. This check will be used to verify input arguments in templated functions, so that they respect the contract that those functions require, so that compilation stops beforehand in case the class and a function are not compatible (i.e. type traits kind of checking).
Thus, I need to be able to verify return type, argument type and number, constness and so on of each member function that I request. The initial question was the checking part of the bigger template that I'm using to verify matches.
A working solution to your problem as posted at https://ideone.com/mxIVw3 is given below - see also live example.
This problem is in a sense a follow-up of Deduce parent class of inherited method in C++. In my answer, I defined a type trait member_class that extracts a class from a given pointer to member function type. Below we use some more traits to analyse and then synthesize back such a type.
First, member_type extracts the signature, e.g. void (C::*)() gives void():
template <typename M> struct member_type_t { };
template <typename M> using member_type = typename member_type_t <M>::type;
template <typename T, typename C>
struct member_type_t <T C::*> { using type = T;};
Then, member_class extracts the class, e.g. void (C::*)() gives C:
template<typename>
struct member_class_t;
template<typename M>
using member_class = typename member_class_t <M>::type;
template<typename R, typename C, typename... A>
struct member_class_t <R(C::*)(A...)> { using type = C; };
template<typename R, typename C, typename... A>
struct member_class_t <R(C::*)(A...) const> { using type = C const; };
// ...other qualifier specializations
Finally, member_ptr synthesizes a pointer to member function type given a class and a signature, e.g. C + void() give void (C::*)():
template <typename C, typename S>
struct member_ptr_t;
template <typename C, typename S>
using member_ptr = typename member_ptr_t <C, S>::type;
template <typename C, typename R, typename ...A>
struct member_ptr_t <C, R(A...)> { using type = R (C::*)(A...); };
template <typename C, typename R, typename ...A>
struct member_ptr_t <C const, R(A...)> { using type = R (C::*)(A...) const; };
// ...other qualifier specializations
The two previous traits need more specialization for different qualifiers to be more generic, e.g. const/volatile or ref-qualifiers. There are 12 combinations (or 13 including data members); a complete implementation is here.
The idea is that any qualifiers are transferred by member_class from the pointer-to-member-function type to the class itself. Then member_ptr transfers qualifiers from the class back to the pointer type. While qualifiers are on the class type, one is free to manipulate with standard traits, e.g. add or remove const, lvalue/rvalue references, etc.
Now, here is your is_foo test:
template <typename T>
struct is_foo {
private:
template<
typename Z,
typename M = decltype(&Z::foo),
typename C = typename std::decay<member_class<M>>::type,
typename S = member_type<M>
>
using pattern = member_ptr<C const, void()>;
template<typename U, U> struct helper{};
template <typename Z> static auto test(Z z) -> decltype(
helper<pattern<Z>, &Z::foo>(),
// All other requirements follow..
std::true_type()
);
template <typename> static auto test(...) -> std::false_type;
public:
enum { value = std::is_same<decltype(test<T>(std::declval<T>())),std::true_type>::value };
};
Given type Z, alias template pattern gets the correct type M of the member pointer with decltype(&Z::foo), extracts its decay'ed class C and signature S, and synthesizes a new pointer-to-member-function type with class C const and signature void(), i.e. void (C::*)() const. This is exactly what you needed: it's the same with your original hard-coded pattern, with the type Z replaced by the correct class C (possibly a base class), as found by decltype.
Graphically:
M = void (Z::*)() const -> Z + void()
-> Z const + void()
-> void (Z::*)() const == M
-> SUCCESS
M = int (Z::*)() const& -> Z const& + int()
-> Z const + void()
-> void (Z::*)() const != M
-> FAILURE
In fact, signature S wasn't needed here, so neither was member_type. But I used it in the process, so I am including it here for completeness. It may be useful in more general cases.
Of course, all this won't work for multiple overloads, because decltype doesn't work in this case.
If you simply want to check the existence of the interface on a given type T, then there're better ways to do it. Here is one example:
template<typename T>
struct has_foo
{
template<typename U>
constexpr static auto sfinae(U *obj) -> decltype(obj->foo(), bool()) { return true; }
constexpr static auto sfinae(...) -> bool { return false; }
constexpr static bool value = sfinae(static_cast<T*>(0));
};
Test code:
struct A {
void foo() {}
};
struct B : public A {
using A::foo;
};
struct C{};
int main()
{
std::cout << has_foo<A>::value << std::endl;
std::cout << has_foo<B>::value << std::endl;
std::cout << has_foo<C>::value << std::endl;
std::cout << has_foo<int>::value << std::endl;
return 0;
}
Output (demo):
1
1
0
0
Hope that helps.
Here's a simple class that passes your tests (and doesn't require a dozen of specializations :) ). It also works when foo is overloaded. The signature that you wish to check can also be a template parameter (that's a good thing, right?).
#include <type_traits>
template <typename T>
struct is_foo {
template<typename U>
static auto check(int) ->
decltype( static_cast< void (U::*)() const >(&U::foo), std::true_type() );
// ^^^^^^^^^^^^^^^^^^^
// the desired signature goes here
template<typename>
static std::false_type check(...);
static constexpr bool value = decltype(check<T>(0))::value;
};
Live example here.
EDIT :
We have two overloads of check. Both can take a integer literal as a parameter and because the second one has an ellipsis in parameter list it'll never be the best viable in overload resolution when both overloads are viable (elipsis-conversion-sequence is worse than any other conversion sequence). This lets us unambiguously initialize the value member of the trait class later.
The second overload is only selected when the first one is discarded from overload set. That happens when template argument substitution fails and is not an error (SFINAE).
It's the funky expression on the left side of comma operator inside decltype that makes it happen. It can be ill-formed when
the sub-expression &U::foo is ill-formed, which can happen when
U is not a class type, or
U::foo is inaccesible, or
there is no U::foo
the resulting member pointer cannot be static_cast to the target type
Note that looking up &U::foo doesn't fail when U::foo itself would be ambiguous. This is guaranteed in certain context listed in C++ standard under 13.4 (Address of overloaded function, [over.over]). One such context is explicit type conversion (static_cast in this case).
The expression also makes use of the fact that T B::* is convertible to T D::* where D is a class derived from B (but not the other way around). This way there's no need for deducing the class type like in iavr's answer.
value member is then initialized with value of either true_type or false_type.
There's a potential problem with this solution, though. Consider:
struct X {
void foo() const;
};
struct Y : X {
int foo(); // hides X::foo
};
Now is_foo<Y>::value will give false, because name lookup for foo will stop when it encounters Y::foo. If that's not your desired behaviour, consider passing the class in which you wish to perform lookup as a template parameter of is_foo and use it in place of &U::foo.
Hope that helps.
I suggest using decltype to generically determine the type of the member function pointers:
helper<decltype(&A::foo), &A::foo> compiles;
helper<decltype(&B::foo), &B::foo> also_compiles;
It may seem like a DRY violation, but repeating the name is fundamentally no worse than specifying the type separately from the name.