Related
I am trying to define a simple variant-based Result type alias, sort of like a poor man's rust-like Result type
:
namespace detail {
template <typename SuccessType, typename... ErrorTypes>
struct Result {
using type = std::variant<SuccessType, ErrorTypes...>;
};
template <typename... ErrorTypes>
struct Result<void, ErrorTypes...> {
using type = std::variant<std::monostate, ErrorTypes...>;
};
} // namespace detail
template <typename SuccessType, typename... ErrorTypes>
using Result_t = detail::Result<SuccessType, ErrorTypes...>::type;
i.e. a Result_t is just an std::variant where the 0th index is the successful result and the rest are error structs.
I defined this helper method to check if the result is good:
template <typename SuccessType, typename... ErrorTypes>
inline bool Ok(const Result_t<SuccessType, ErrorTypes...>& r) {
return r.index() == 0;
}
But I get a "no matching overloaded function found" when I try to instantiate it:
error C2672: 'Ok': no matching overloaded function found
error C2783: 'bool Ok(const detail::Result<SuccessType,ErrorTypes...>::type &)': could not deduce template argument for 'SuccessType'
struct FileError {};
struct BadJson {};
template <typename T>
using Result = Result_t<T, FileError, BadJson>;
Result<void> GetVoid() { return {}; }
TEST(ConfigFileTest, Result) {
auto res = GetVoid();
EXPECT_EQ(res.index(), 0);
bool ok = Ok(res);
EXPECT_TRUE(ok);
}
What am I doing wrong? If I just have Ok be templated like template <typename T> Ok(const T& r) it works, but makes the function too general.
After expanding the Result_t alias in the function parameter, it looks like this:
template <typename SuccessType, typename... ErrorTypes>
bool Ok(const detail::Result<SuccessType, ErrorTypes...>::type& r) {
return r.index() == 0;
}
The problematic part here is that the template parameters are left of the name resolution operator ::. Everything left of :: is a non-deduced context, meaning that it is not used to deduce template arguments. So since SuccessType and ErrorTypes... appear only in non-deduced context, they cannot be deduced and a call which doesn't explicitly specifies them will fail.
You can see that this rule is necessary, because theoretically any specialization of detail::Result<SuccessType, ErrorTypes...> could have a ::type that matches the arguments type. There is no way that the compiler can check this for every possible combination of types.
Instead of trying to alias types, make Result an actual new type:
template <typename SuccessType, typename... ErrorTypes>
struct Result {
using variant_type = std::variant<SuccessType, ErrorTypes...>;
variant_type variant;
};
template <typename... ErrorTypes>
struct Result<void, ErrorTypes...> {
using variant_type = std::variant<std::monostate, ErrorTypes...>;
variant_type variant;
};
template <typename SuccessType, typename... ErrorTypes>
bool Ok(const Result<SuccessType, ErrorTypes...>& r) {
return r.variant.index() == 0;
}
or something along those lines. If you really want to use the old design using only aliases, then the function should not take the nested alias as argument, but the actual type instead (which is probably not match the intent of the design):
template <typename T, typename... ErrorTypes>
bool Ok(const std::variant<T, ErrorTypes...>& r) {
return r.index() == 0;
}
(I removed the inline on the templates. inline on a function template doesn't really make much sense.)
I am writing a C++ network library and would like the main (template) function to accept parameters in random order, to make it more user friendly, in the same way the CPR library does.
The template function will accept up to 10 parameters at the same time, each a different type. Is there a way to instantiate the template to accept any random order of param types, other than having to manually include code for every possibility?
For example - in this case using 3 params each a different type:
.h file
namespace foo
{
template <typename T, typename U, typename V> void do(const T& param_a, const U& param_b , const V& param_c);
};
.cpp file
template <typename T, typename U, typename V>
void foo::do(const T& param_a, const U& param_b, const V& param_c) {
//do lots of stuff
}
//instantiate to allow random param order
template void foo::do<int, std::string, long>(const int&, const std::string&, const long&);
template void foo::do<int, long, std::string>(const int&, const long&, const std::string&);
template void foo::do<int, std::string, int>(const int&, const std::string&, const int&);
//etc... to cover all possible param orders
If your goal is to match the API design of a given library, best way to learn is to dig into its source code and dissect it.
Consider this snippet of code (I'm still using CPR as an example as you mentionned it as a reference):
cpr::Session session;
session.SetOption(option1);
session.SetOption(option2);
session.SetOption(option3);
You want a method which can handle option1, option2, ... , no matter in which order they are provided. The subsequent calls to SetOption could be replaced with a single SetOptions(option3, option1, option2). Therefore we need a variadic SetOptions method:
template<typename Ts...> // important: don't specialize the possible argument types here
void SetOptions(Ts&&... ts)
{ /* do something for each param in ts... */ }
The question is "how do you call SetOption for each item inside the ts parameter-pack ?". This is a mission for std::initializer_list. You can find a simple example here.
The key here is to have an overloaded function which can handle each argument type separately (example in CPR with SetOptions). Then, inside your "permutable" function, you call the overloaded function for each of your arguments, one at a time (example in CPR, which is then used in various places).
One thing to note though is that you can pass multiple parameters of the same type. Depending on what you want to achieve, this can be an issue or not.
Also, you can call the method with unsupported argument types (matching none of your overloads), in this case the error message is not always explicit depending on which compiler you are using. This is — however — something you could overcome using static_asserts.
Is there a way to instantiate the template to accept any random order of param types, other than having to manually include code for every possibility?
You cannot do this for explicit instantiation definitions without macros, but you could use a separate approach and rely on implicit instantiations instead, using SFINAE to restrict the primary template (whose definition you move to the header file) based on two custom traits.
To begin with, given the following type sequence
template <class... Ts>
struct seq {};
we want to construct a trait that, for a given type sequence seq<T1, T2, ...> (your "10 parameter types"), denoted as s:
s shall be a subset of set of types of your choosing seq<AllowedType1, ...>, and
s shall contain only unique types.
We can implement the former as:
#include <type_traits>
template <class T, typename... Others>
constexpr bool is_same_as_any_v{(std::is_same_v<T, Others> || ...)};
template <typename, typename> struct is_subset_of;
template <typename... Ts, typename... Us>
struct is_subset_of<seq<Ts...>, seq<Us...>> {
static constexpr bool value{(is_same_as_any_v<Ts, Us...> && ...)};
};
template <typename T, typename U>
constexpr bool is_subset_of_v{is_subset_of<T, U>::value};
and the latter as
template <typename...> struct args_are_unique;
template <typename T> struct args_are_unique<T> {
static constexpr bool value{true};
};
template <typename T, typename... Ts> struct args_are_unique<seq<T, Ts...>> {
static constexpr bool value{!is_same_as_any_v<T, Ts...> &&
args_are_unique<seq<Ts...>>::value};
};
template <typename... Ts>
constexpr bool args_are_unique_v{args_are_unique<Ts...>::value};
after which we can define the primary template as
namespace foo {
namespace detail {
using MyAllowedTypeSeq = seq<int, long, std::string>; // ...
} // namespace detail
template <
typename T, typename U, typename V, typename Seq = seq<T, U, V>,
typename = std::enable_if_t<is_subset_of_v<Seq, detail::MyAllowedTypeSeq> &&
args_are_unique_v<Seq>>>
void doStuff(const T ¶m_a, const U ¶m_b, const V ¶m_c) {
// do lots of stuff
}
} // namespace foo
and where we may and may not use the primary template overload as follows:
int main() {
std::string s{"foo"};
int i{42};
long l{84};
foo::doStuff(s, i, l); // OK
foo::doStuff(s, l, i); // OK
foo::doStuff(l, i, s); // OK
foo::doStuff(l, s, i); // OK
// uniqueness
foo::doStuff(l, l, i); // Error: candidate template ignored
// wrong type
unsigned int ui{13};
foo::doStuff(s, ui, l); // Error: candidate template ignored
}
If types need not actually be unique (it's somewhat unclear from the question) you can simply SFINAE-constrain the primary template only on the first is_subset_of_v trait:
template <
typename T, typename U, typename V, typename Seq = seq<T, U, V>,
typename = std::enable_if_t<is_subset_of_v<Seq, detail::MyAllowedTypeSeq>>>
void do(const T ¶m_a, const U ¶m_b, const V ¶m_c) {
// do lots of stuff
}
Why not use the builder pattern here? You would create a foo_builder with various setXxx methods and a final build() to get the fully configured object.
Use a struct to hold all the params.
namespace foo
{
struct do_params {
int a;
long b;
std::string c;
};
void do(do_params params);
};
Here is my code:
template<
template <typename TSEvent,
typename ...TSEvents> typename V,
typename... Filtered>
constexpr auto filter() {
if constexpr(sizeof...(TSEvents) == 0) {
return type_list<Filtered...>{};
}
if constexpr(is_default_constructible<TSEvent>::value) {
return filter<<TSEvents...>, Filtered...>();
}
return filter<<TSEvents...>, Filtered...>();
}
I however get this error, size...(TSEvents), TSEvents is not declared. Is there anyway for me to access TSEvents in my nested template?
Usually through another level of indirection, and usually a struct that we can specialize.
For example:
namespace detail
{
template<class...>
struct filter_t;
template<template<class, class...> class V, class TSEvent, class... TSEvents, class... Filtered>
struct filter_t<V<TSEvent,TSEvents...>, Filtered...>
{
static constexpr auto filter() {
return sizeof...(TSEvents);
}
};
} // detail
template<class... T>
constexpr auto filter()
{
return detail::filter_t<T...>::filter();
}
template<class T, class...U>
struct type_list{};
int main()
{
std::cout << filter<type_list<int, int, int>, int>();
}
Live Demo
Just to present another option, you could do this with only functions.
#include <iostream>
using namespace std;
template<typename...>
struct type_list{};
template < template <typename...> typename T,typename A,typename... B, typename... Filtered>
constexpr auto filter_impl(T<A,B...>*,type_list<Filtered...>)
{
using filtered_list = std::conditional_t<is_arithmetic<A>::value,
type_list<Filtered...,A>,
type_list<Filtered...>>;
if constexpr (sizeof...(B) == 0)
return filtered_list();
else
return filter_impl( (T<B...>*)0, filtered_list());
}
template <typename T>
constexpr auto filter()
{
return filter_impl( (T*)0,type_list<>());
}
struct not_arethmetic{};
int main() {
auto b = filter< type_list<not_arethmetic,int,bool,not_arethmetic,double> >();
static_assert(std::is_same< decltype(b) , type_list<int,bool,double>>::value);
return 0;
}
Demo
One thing, In your original example your first if expression will mean that the final TSEvent is not checked, as it returns if the varadic TSEvents... is zero size, but there will be one final element to check whether is_default_constructible.
Also, you might find this post useful regarding template template parameter names.
I however get this error, size...(TSEvents), TSEvents is not declared. Is there anyway for me to access TSEvents in my nested template?
Short answer: no.
Long answer: with
template<
template <typename TSEvent,
typename ...TSEvents> typename V,
typename... Filtered>
constexpr auto filter()
you set two template arguments for the filter() function.
The first one, related to the TSEvents variadic list, is a template-template argument that receive one or more types argument.
But your function doesn't receive a type that is based over that template-template (with a fixed TSEvent type and a fixed TSEvents); receive the template-template.
So doesn't make sense the test size...(TSEvents) because, for filter() isn't
fixed the TSEvents list.
To explain this in another way... you can call filter this way
filter<std::tuple, short, int, long>();
Ask for sizeof...(TSEvents) is asking how many types contains std::tuple where std::tuple is only the container of types but without contained types.
If you want to make some sort of actions in your filter() function, you need a type template parameter, not a template-template parameter.
It's simpler with classes (see AndyG's answer) where you can use partial specialization (with functions you can't) or with function when they receive arguments from which you can deduce types.
Suppose your filter() receive an object of type V<SomeTypes...> and an object of type std::tuple<Filtered...>, you can write something as follows (caution: code not tested)
template<
template <typename ...> typename V,
typename TSEvent, typename ... TSEvents, typename... Filtered>
constexpr auto filter (V<TSEvent, TSEvents...> const & v,
std::tuple<Filtered...> const & t) {
/* some code where you can use also TSEvent and TSEvents... */
}
This way TSEvent and TSEvents... are deduced from the v argument.
I've got a template c++ object as follows
template <typename T, Dimension D>
class Field : public std::vector<T>
{
// ... lot of stuff ...
T differentiate(const gridPoint<D>&, int) const;
};
This differentiate methode is computed differently depending of the Dimension D
enum Dimension : std::size_t { _2D = 2, _3D = 3 };
I could just put a switch inside the method's body bt I'd like to use the templates in order to help with clarity
I tried using std::enable_if like this:
template <typename T, Dimension D>
typename std::enable_if<D==_2D, T>::type
Field<T,D>::differentiate(const gridPoint<D>& pt, int extent) const
{
// ... lot of computation
}
template <typename T, Dimension D>
typename std::enable_if<D==_3D, T>::type
Field<T,D>::differentiate(const gridPoint<D>& pt, int extent) const
{
// ... even more computation
}
but the compiler tels me that my implementation doesn't match any prototypes
What did I do wrong ? I just can't figure out how i'm suppose to declare the method's code
You can probably save yourself a lot of hassle and unreadable code in the long run by writing distinct partial specializations of Field for the 2D and 3D case:
enum Dimension : std::size_t { _2D = 2, _3D = 3 };
template <Dimension D>
using gridPoint = std::array<int, D>;
template <typename T>
struct Field_base : std::vector<T> {
// Stuff common to both specializations goes here.
using std::vector<T>::vector;
};
template <typename, Dimension>
struct Field;
template <typename T>
struct Field<T, _2D> : Field_base<T>
{
using grid_point = gridPoint<_2D>;
using Field_base<T>::Field_base;
T differentiate(const grid_point&, int) const
{
std::cout << "2D differentiate called\n";
return {};
}
};
template <typename T>
struct Field<T, _3D> : Field_base<T>
{
using grid_point = gridPoint<_3D>;
using Field_base<T>::Field_base;
T differentiate(const grid_point&, int) const
{
std::cout << "3D differentiate called\n";
return {};
}
};
For SFINAE to work, I believe the function needs to be templated so that this becomes a choice of which function compiles during overload resolution, not which function compiles during class instantiation.
I modified this as follows and it "works" on this end:
#include <iostream>
#include <vector>
enum Dimension : std::size_t { _2D = 2, _3D = 3 };
template <Dimension D>
struct gridPoint
{
int d[D];
};
template <typename T, Dimension D>
struct Field : public std::vector<T>
{
template <Dimension D2>
typename std::enable_if<D== D2 && D==_2D, T>::type
differentiate(const gridPoint<D2>& pt, int extent) const
{
std::cout << "2D differentiate called" << std::endl;
return T(0.0);
}
template <Dimension D2>
typename std::enable_if<D==D2 && D==_3D, T>::type
differentiate(const gridPoint<D2>& pt, int extent) const
{
std::cout << "3D differentiate called" << std::endl;
return T(0.0);
}
};
int main() {
Field<double, _2D> foo;
gridPoint<_2D> point { 3, 4 };
foo.differentiate(point, 3);
gridPoint<_3D> p3 { 3, 4, 5 };
Field<double, _3D> bar;
bar.differentiate(p3, 8);
return 0;
}
I didn't sort out the template foo to get this to compile with the definition out-of-line.
The compiler error provoked by your attempted out-of-line SFINAE definitions
for T Field<T,Dimension>::differentiate(const gridPoint<D>&, int) const would be:
error: prototype for ‘typename std::enable_if<(D == _2D), T>::type Field<T, D>::differentiate(const gridPoint<D>&, int) const’ does not match any in class ‘Field<T, D>’
error: candidate is: T Field<T, D>::differentiate(const gridPoint<D>&, int) const
error: prototype for ‘typename std::enable_if<(D == _3D), T>::type Field<T, D>::differentiate(const gridPoint<D>&, int) const’ does not match any in class ‘Field<T, D>’
error: candidate is: T Field<T, D>::differentiate(const gridPoint<D>&, int) const
or words to that effect.
The compiler insists that any purported out-of-line definition of a member function
of Field<T,Dimension> has the same prototype as the declaration of
of some member function, and its diagnostics spell out that this requirement is
not satisfied for either of the purported out-of-line definitions.
It is no good protesting that if the compiler would just carry on and do the SFINAE,
it then would discover that the one surviving out-of-line definition matches a member function declaration. It can't do
the SFINAE until it attempts some instantiation of Field<D,Dimension>, and making sure that
any out-of-line template/class member definitions pair off with template/class member declarations comes earlier on its
to-do list than instantiating templates. Instantiation might never happen, but orphan
member definitions are always wrong.
So, both of those SFINAE-embellished prototypes would have to appear as member
function declarations.
But then, if the compiler is to tolerate both of these SFINAE-embellished member
function declarations, they must be template member functions (not merely
member functions of a class template) and their respective std::enable_if conditions
must depend upon a template parameter of the member function. Such are the SFINAE
rules.
Summing up, what you need to write to accomplish your out-of-line SFINAE definitions is
illustrated by the following program:
#include <iostream>
#include <vector>
enum Dimension : std::size_t { _2D = 2, _3D = 3 };
template<Dimension D>
struct gridPoint {}; // ...whatever
template <typename T, Dimension D>
class Field : public std::vector<T>
{
public:
template <Dimension Dim = D>
typename std::enable_if<Dim ==_2D, T>::type
differentiate(const gridPoint<Dim>&, int) const;
template <Dimension Dim = D>
typename std::enable_if<Dim ==_3D, T>::type
differentiate(const gridPoint<Dim>&, int) const;
};
template <typename T, Dimension D> template<Dimension Dim>
typename std::enable_if<Dim ==_2D, T>::type
Field<T,D>::differentiate(const gridPoint<Dim>& pt, int extent) const
{
std::cout << "_2D differentiate" << std::endl;
return T(); // ...whatever
}
template <typename T, Dimension D> template<Dimension Dim>
typename std::enable_if<Dim ==_3D, T>::type
Field<T,D>::differentiate(const gridPoint<Dim>& pt, int extent) const
{
std::cout << "_3D differentiate" << std::endl;
return T(); // ...whatever
}
int main()
{
Field<int,_2D> f_2d;
gridPoint<_2D> gp_2d;
f_2d.differentiate(gp_2d,2);
Field<float,_3D> f_3d;
gridPoint<_3D> gp_3d;
f_3d.differentiate(gp_3d,3);
f_3d.differentiate(gp_2d,2);
return 0;
}
In this not very pleasant light, you might possibly want to review the question of whether Dimension needs to be a template parameter of
Field, or whether it might just be a template parameter of member functions of Field. As I
don't know the complete implementation of the template, I can't say. Alternatively, you might reconsider your dislike of the
template base class + partial specialization approach suggested by #casey.
Presumably you would like the alternative definitions of differentiate out-of-line because they are big and you don't want them
sprawling in the body of the class template. In thorny cases like this a plodding but fairly failsafe way of extruding template/class member definitions to be out-of-line
is first to code the template/class with inline definitions and get a successful build; then copy-paste the inline definitions to their
out-of-line places, add the required template/class qualifications and delete default specifiers; then truncate the original in-line definitions to declarations;
then get a successful build again.
The output of that example program is:
_2D differentiate
_3D differentiate
_2D differentiate
The last line is emitted by the execution f_3d.differentiate(gp_2d,2), which draws attention to the fact that the selected implementation of differentiate
is determined by the Dimension of the gridPoint<Dimension>& argument that is passed to it and not by the Dimension of the
Field<T,Dimension> on which it is invoked. Thus we can call Field<T,_3D>::differentiate<_2D>. Since you said:
This differentiate methode is computed differently depending of the Dimension D
this on the face of it seems to be the behaviour you want, as the gridPoint<Dimension>
argument differentiates the implementations of differentiate according to the value of
Dimension. But this observation revives the question: Is there really a good reason for
Dimension to be a template parameter of Field, and not just a template parameter of differentiate?
If there is really a good reason, then you want it to be impossible to call Field<T,_3D>::differentiate<_2D>
or Field<T,_2D>::differentiate<_3D>. You can achieve that by replacing all occurrences of <Dim> with
<D> in the program, though the SFINAE implementation then looks even more laboured.
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.