Reflection in known set of classes - c++

I am trying to iterate through an object hierarchy and the object hierarchy is composed of a known set of classes combined using composition. I would like to build an object model to show the hierarchy / composition graphically. The composition is done based on few rules but it is fluid and flexible.
Quite a few classes (25+) are available and the number of building blocks is increasing. If I search each type in every other type then we have a significantly large number of combinations possible.
I could build a large table where I search for each of the other objects for a given type and recursively build the object model but may be there is a better way and so here I am asking the experts.
Is it possible to know if a function / member variable is present on a particular type at runtime.
My sample code is shown below :
#include <iostream>
struct Generic {};
struct SimpleType {int toString(){return 0;}};
enum ETypeVal{eVal1 = 0, eVal2 = 1, eVal3 = 2};
template <typename ETypeVal val>
struct Hello
{
int toString(){return 0;}
};
template <> struct Hello<eVal2>
{
int toString(){return 1;}
};
template <> struct Hello<eVal3>
{
};
template <class Type>
class TypeHasToString
{
public:
typedef bool Yes;
typedef short No;
static bool const value = (sizeof(HasToString<Type>(0)) == sizeof(Yes));
private:
template <typename T, T> struct TypeCheck;
template <typename T> struct ToString
{
typedef int (T::*fptr)();
};
template <typename T> static Yes HasToString(TypeCheck< typename ToString<T>::fptr, &T::toString >*);
template <typename T> static No HasToString(...);
};
int main(int argc, char *argv[])
{
// all this works fine
std::cout << TypeHasToString<Generic>::value << std::endl;
std::cout << TypeHasToString<SimpleType>::value << std::endl;
std::cout << TypeHasToString<Hello<eVal1>>::value << std::endl;
std::cout << TypeHasToString<Hello<eVal2>>::value << std::endl;
std::cout << TypeHasToString<Hello<eVal3>>::value << std::endl;
// Unable to deduce for type that are not known at compile time
// Is it possible to remove this limitation ?
for(int val = eVal1; val <= eVal3; val++)
{
std::cout << TypeHasToString< Hello< (ETypeVal)val > >::value << std::endl;
}
return 0;
}

I've used boost::mpl to do the iteration and printing of the values. Most of this should be possible without any of those, but I heavily recommend using it. Also I've fixed some things in your code. You might also want to use BOOST_HAS_XXX instead of your homebrew solution (your SFINAE style is rather awkward).
#include <iostream>
#include <boost/mpl/vector.hpp>
#include <boost/mpl/range_c.hpp>
#include <boost/mpl/transform.hpp>
#include <boost/mpl/for_each.hpp>
struct Generic {};
struct SimpleType {int toString(){return 0;}};
enum ETypeVal{ eVal1 = 0, eVal2 = 1, eVal3 = 2};
template <ETypeVal val>
struct Hello
{
int toString(){return 0;}
};
template <> struct Hello<eVal2>
{
int toString(){return 1;}
};
template <> struct Hello<eVal3>
{
};
template <class Type>
class TypeHasToString
{
public:
typedef bool Yes;
typedef short No;
private:
template <typename T, T> struct TypeCheck;
template <typename T> struct ToString
{
typedef int (T::*fptr)();
};
template <typename T> static Yes HasToString(TypeCheck< typename ToString<T>::fptr, &T::toString >*);
template <typename T> static No HasToString(...);
public:
static bool const value = (sizeof(HasToString<Type>(0)) == sizeof(Yes));
};
template<typename val>
struct make_hello { typedef Hello< ETypeVal(val::value)> type; };
struct print_seq {
template<typename T>
void operator()(const T&) const {
std::cout << T::value << std::endl;
}
};
int main()
{
using namespace boost::mpl;
// maybe have a last enum here
typedef range_c<int, eVal1, eVal3 + 1>::type range;
// range has no clear so we need the inserter
typedef transform<range, make_hello<_1>, back_inserter< vector0<> > >::type hellos;
typedef transform< hellos, TypeHasToString<_1> >::type booleans;
// namespace for clarity
boost::mpl::for_each<booleans>( print_seq() );
return 0;
}

We don't have run-time reflection in C++. But we have different stuff, that most C++ programmers like better than reflection ;-).
If I understand your question, you need to build some sort of object browser, and you know all your object types. By "you know all your object types" I mean "you won't get an object as something at the other end of a pointer from a dll you didn't code".
So, maybe you can use boost::fusion? Said library is designed for iterating through aggregates, and while doing so, retrieving both data and type of each aggregate member. It is like iterators over struct members, if I have to put it in a flowery way. You can of course use it with your custom types.

You can't know at runtime if you don't at compile time. You have the code to know at compile time for one function. You could just make a macro out of it to have it for any function you want to check. (Macro disclaimer: in this case macros are good, that's how BOOST_MPL_HAS_XXX_TEMPLATE_DEF works).
Alternatively, there's boost::fusion as mentionned by dsign. But I prefer another one: boost::reflect (not actully in boost more info here). The macro syntax is easier (you don't need to mention the type in the macro) and the code is very lightweight. Then there's the feature complete boost::mirror (download here), not yet in boost, that is much more complete and even has a code generator to create the macro calls for you and a java style runtime reflection.

I think that you need the runtime polymorphism in this case. Use interfaces instead of templates for such kind of problems. Interfaces will give the knowledge about of the methods in your object but will say nothing about the member variables. So there is no reflection available in standard c++ (the only thing that c++ provides is the type_info operator which might help you in some cases), you could try to find some extensions for your compiler which will give you the reflection opportunities.

Related

How to decompose a pointer-to-member in C++ (get class and member types)?

I have this scenario:
#include <iostream>
class SomeClass
{
public:
int _int;
};
#define DO_SOME_STUFF(ptr) std::cout << /* Print the typeid().hash_code() of the type which ptr is poiting to (int) */;
int main()
{
int SomeClass::* ptr_to_int_member = &SomeClass::_int;
DO_SOME_STUFF(ptr_to_int_member)
}
I want to know which type is ptr pointing at (which is currently int).
Knowing which class owns that int is also useful (which is currently SomeClass).
You can do that with a "template trick":
template<typename T>
struct PointerToMemberDecomposer {};
template<typename T, typename P>
struct PointerToMemberDecomposer<P T::*>
{
using ClassType = T;
using MemberType = P;
};
And change your code to:
#include <iostream>
template<typename T>
struct PointerToMemberDecomposer {};
template<typename T, typename P>
struct PointerToMemberDecomposer<P T::*>
{
using ClassType = T;
using MemberType = P;
};
class SomeClass
{
public:
int _int;
};
#define DO_SOME_STUFF(ptr) std::cout << typeid(PointerToMemberDecomposer<decltype(ptr)>::MemberType).hash_code();
int main()
{
int SomeClass::* ptr_to_int_member = &SomeClass::_int;
DO_SOME_STUFF(ptr_to_int_member)
}
Defining a couple of templated aliases can make the code a little bit cleaner:
#define GET_POINTER_TO_MEMBER_CLASS_TYPE(ptr) PointerToMemberDecomposer<decltype(ptr)>::ClassType
#define GET_POINTER_TO_MEMBER_MEMBER_TYPE(ptr) PointerToMemberDecomposer<decltype(ptr)>::MemberType
So you can change DO_SOME_STUFF to:
#define DO_SOME_STUFF(ptr) std::cout << typeid(GET_POINTER_TO_MEMBER_MEMBER_TYPE(ptr)).hash_code();
Explanation
This technique is called Partial template specialization.
The second definition of PointerToMemberDecomposer will be used when a pointer-to-member type is passed as template argument; And will catch new T and P typenames. using those new typenames; It will define two type aliases (ClassType and MemberType) so T and P can be used outside of the PointerToMemberDecomposer struct.
When using PointerToMemberDecomposer; you should use decltype operator which acts like type in Python or typeof in C#. decltype(x) passes the type of x instead of x itself.
Update
As 463035818_is_not_a_number have mentioned; macros can be replaced with templated aliases
template <typename T>
using ClassTypeFromPtrToMember_t = typename PointerToMemberDecomposer<T>::ClassType;
template <typename T>
using MemberTypeFromPtrToMember_t = typename PointerToMemberDecomposer<T>::MemberType;
But you should still use decltype while DO_SOME_STUFF is a macro instead of a templated function and we cant access ptr's type directly (see 463035818_is_not_a_number's answer for templated function version of DO_SOME_STUFF):
#define DO_SOME_STUFF(ptr) std::cout << typeid(MemberTypeFromPtrToMember_t<decltype(ptr)>).hash_code();
In this case; DO_SOME_STUFF can be converted to a templated function. But you might want to for example fill a non capturing lambda with macro arguments; which requires DO_SOME_STUFF to be a macro.
Also, you might want to change ClassType and MemberType to type and create two separated structs (or classes) for retrieving those type aliases; If you want PointerToMemberDecomposer to look like C++'s standard library.
For more details; see 463035818_is_not_a_number's answer
Just summarizing comments to some otherwise great answer...
Member aliases are commonly named just type. Macros are better avoided (Why are preprocessor macros evil and what are the alternatives?) and for less verbosity on the caller you can use a function template:
#include <iostream>
#include <typeinfo>
template<typename T>
struct TypeFromPtrToMember; // needs no definition
template<typename T, typename P>
struct TypeFromPtrToMember<P T::*>
{
using type = T;
};
class SomeClass
{
public:
int _int;
};
template <typename T>
void do_some_stuff(T t){
std::cout << typeid(typename TypeFromPtrToMember<T>::type).hash_code();;
}
int main()
{
int SomeClass::* ptr_to_int_member = &SomeClass::_int;
do_some_stuff(ptr_to_int_member);
}
Naming the member alias type is so common that I would do it even if you then need two traits. The other trait is basically the same just with using type = P;.
In the above, there is still the little annoyance of having to write typename when using the trait (because TypeFromPtrToMember<T>::type is a dependent name). Since C++11 we can use a template alias to help with that. Template aliases cannot be partially specialized, but we already have the trait and just need to forward to that:
template <typename T>
using TypeFromPtrToMember_t = typename TypeFromPtrToMember<T>::type;
Such that do_some_stuff can be:
template <typename T>
void do_some_stuff(T t){
std::cout << typeid(TypeFromPtrToMember_t<T>).hash_code();;
}
I hope you agree that now no macros are needed anymore.

How is nested template specialization done C++

I have a templated function defined as:
template<typename TObject> TObject Deserialize(long version, const Value &value)
what I need to do, is to write a specialization which would take vector defined as:
template<typename TNum, int cnt> class Vec
and still has access to cnt and TNum.
I have unsuccesfully tried
template<typename TNum, int cnt> Vec<TNum, cnt> Deserialize<Vec<TNum, cnt>>(long version, Value &value)
resulting in error: illegal use of explicit template arguments
What is the correct way to do it?
Usually, the correct answer to dealing with function templates and needing to partially specialize them, is to simply overload them instead. In this case this trick doesn't work directly because there are no arguments that depend on the template parameter, i.e. the template parameter is explicitly specified and not deduced. However, you can forward along to implementation functions, and make overloading work by using a simple tag struct.
#include <functional>
#include <iostream>
#include <type_traits>
#include <vector>
#include <array>
template <class T>
struct tag{};
template<typename TObject>
TObject Deserialize_impl(long version, tag<TObject>) {
std::cerr << "generic\n";
return {};
}
template<typename T, std::size_t N>
std::array<T,N> Deserialize_impl(long version, tag<std::array<T,N>>) {
std::cerr << "special\n";
return {};
}
template<typename TObject>
TObject Deserialize(long version) {
return Deserialize_impl(version, tag<TObject>{});
}
int main() {
Deserialize<int>(0);
Deserialize<std::array<int,3>>(0);
return 0;
}
Live example: http://coliru.stacked-crooked.com/a/9c4fa84d2686997a
I generally find these approaches strongly preferable to partial specialization of a struct with a static method (the other major approach here) as there are many things you can take advantage with functions, and it behaves more intuitively compared to specialization. YMMV.
While the functional tag-dispatch is a nice approach, here's a class specialization version for comparison. Both have their use, and I don't think either is an inherently regrettable decision but maybe one matches your personal style more.
For any class you write that needs a custom deserialize handler, just write a specialization of the Deserializer class:
#include <iostream>
#include <string>
using namespace std;
using Value = std::string;
// default deserialize function
template <typename TObject>
struct Deserializer {
static TObject deserialize(long version, const Value &value) {
std::cout << "default impl\n";
return TObject();
}
};
// free standing function (if you want it) to forward into the classes
template <typename TObject>
TObject deserialize(long version, const Value &value) {
return Deserializer<TObject>::deserialize(version, value);
}
// Stub example for your Vec class
template<typename TNum, int cnt> class Vec { };
// Stub example for your Vec deserializer specialization
template <typename TNum, int cnt> struct Deserializer<Vec<TNum, cnt>> {
static auto deserialize(long version, const Value &value) {
std::cout << "specialization impl: cnt=" << cnt << "\n";
return Vec<TNum, cnt>();
}
};
int main() {
Value value{"abcdefg"};
long version = 1;
deserialize<int>(version, value);
deserialize<Vec<int, 10>>(version, value);
}
Ideally in this situation, Vec should reflect its own template parameters as members Vec::value_type and Vec::size() which should be constexpr.
If the class fails to provide its own properties in its own interface, the next best thing is to define your own extension interface. In this situation, you can have separate metafunctions (like accessor functions), or a traits class (like a helper view class). I'd prefer the latter:
template< typename >
struct vector_traits;
template< typename TNum, int cnt >
struct vector_traits< Vec< TNum, cnt > > {
typedef TNum value_type;
constexpr static int size = cnt;
};
template<typename TVec> TVec Deserialize(long version, Value &value) {
typedef vector_traits< TVec > traits;
typedef typename traits::value_type TNum;
constexpr static int cnt = traits::size;
…
}
This solution fits into any existing function, and even makes the signatures cleaner. Also, the function is more flexible because you can adapt it by adding traits specializations instead of entire new overloads.

C++ template for variable type declaration

I have a number of classes with differing members, all of which have operations of the following type
::basedata::Maindata maindata;
::basedata::Subdata subinfo("This goes into the subinfo vector");
subinfo.contexts(contextInfo);
maindata.subdata().push_back(subinfo);
Note that I am asking how to set up generalized templates to perform these actions. I cannot set up a special case for each type of maindata and subinfo. I also need to be able to see how to call the template from my main code. I have been able to set up a template if maindata.subdata() exists, but keep getting a compilation failure on a call to the template if it does not exist. That is create the template of the form
perform_Push(maindata.subdata(), subinfo);
so that it can be compiled whether or not maindata.subdata() exists or not.
I could accept templates that build so that the main code can show
bool retval
retval = hasmember(maindata, subdata);
if (retval)
{
buildmember(maindata.subdata, subinfo);
setAttributes(subinfo, data);
perform_Push(maindata.subdata(), subinfo)
}
else
{
// Perform alternate processing
}
As of now, the code inside the if would not compile when the templates being called should just be void.
While ::basedata::Maindata is always defined, ::basedata::Subdata may or may not be defined depending on the release of libraries that my code is being build with. subdata is defined as a vector belonging to maindata which therefore has the push_back() operation defined. There are too many types of subData to create a separate template for each type as T::Subdata within a template in any case.
That is, if subdata was the only case, I could create a specialization of the template T as ::maindata::subdata and a generic Template T.
I do not have any control of the include files or library that for this so that I cannot create a #define of a variable to test with the pre-compiler. Is there a good way of setting up a template that would allow this to work? I could use a template that returns a boolean true (success) or false (no such definition) and call the alternate processing at run time. I would not need to have an alternate template.
Basically, I am asking how to apply SFINAE to this particular situation.
I have managed to figure out what I need to do to set up the basic template
If I have the most basic operation
maindata.subdata().push_back(data)
I can define a template of the form,
<template class T, typename D>
auto doPush(D data) -> decltype(T.pushback(data), void())
{
T.push_back(data);
}
and the call would be
doPush<maindata.subdata()>(data);
However, the problem would be how to set it up when maindata does not yet have a member subdata.
You can use this templates to obtain a boolean value that tell you if exist member type Subdata in a generic type T. This works only if T is a struct/class not a namespace.
#include <type_traits>
template <class T, class V = void>
struct hasSubdata
{
enum { value = false };
};
template <class T>
struct hasSubdata<T, typename std::enable_if< std::is_same<typename T::Subdata, typename T::Subdata>::value >::type>
{
enum { value = true };
};
struct basedata1
{
struct Subdata {};
};
struct basedata2
{
};
#include <iostream>
int main ()
{
std::cout << "basedata1: " << hasSubdata<basedata1>::value << std::endl;
std::cout << "basedata2: " << hasSubdata<basedata2>::value << std::endl;
}
But you can't use a normal if because the compiler checks the correctness of all the possibilities.
You have to act in a similar way (pretty ugly):
template <class T, bool = hasSubdata<T>::value>
struct SubdataUser
{
static void foo ()
{
std::cout << "I can use SubData member :)" << std::endl;
typename T::Subdata subinfo ();
}
};
template <class T>
struct SubdataUser<T, false>
{
static void foo ()
{
std::cout << "I can not :(" << std::endl;
}
};
int main ()
{
SubdataUser<basedata1>::foo ();
return 0;
}
Unfortunately to my knowledge, you can not have a template hasMember<Type,Member>::value because if Member does not exist, compilation fails.
But you might like a solution of this type
#include <type_traits>
#include <iostream>
struct basedata1
{
struct Subdata1 {};
struct Subdata2 {};
struct Subdata3 {};
};
struct basedata2
{
struct Subdata1 {};
//struct Subdata2 {};
struct Subdata3 {};
};
template <class...>
struct Require
{
enum { value = true };
};
template <class T, bool = true>
struct Impl
{
static void foo ()
{
std::cout << "At least one of the members required is not available :(" << std::endl;
}
};
template <class T>
struct Impl<T, Require< typename T::Subdata1,
typename T::Subdata2,
typename T::Subdata3 >::value >
{
static void foo ()
{
std::cout << "All members are available :)" << std::endl;
typename T::Subdata2 my_var;
}
};
int main( int argc, char* argv[] )
{
Impl<basedata1>::foo ();
Impl<basedata2>::foo ();
return 0;
}
I hope this helps
I have managed to figure out what I need to do to set up the basic template as well as the member template. It is actually two different questions and two different answer templates. It requires a basic generic template called by a specific member template.
C++ preprocessor test if class member exists

Dynamic namespace usage based on a template parameter

I don't know if that is feasable at all, but this is what I'd like to achieve : in a templated class I would like to be using the namespace of the template parameter.
eg.
template<class P>
class Foo
{
public:
Foo();
virtual ~Foo();
void doSomething(P&);
void doSomethingElse();
protected:
// There I'm hardcoding "namespace1" but that's what I'd like to
// be possibly dynamic
// (I'm assuming template parameter P = namespace1::Type)
void method1(namespace1::Type1&);
...
void methodN(namespace1::TypeN&);
}
// Again, supposing P == namespace1::Type then I want to be using namespace1
// everywhere in the implementation...
using namespace namespace1;
template<class P>
void Foo<P>::doSomething(P& parameter)
{
...
Type1 type1 = P.getType1(); // There namespace1::Type1 is returned !!
method1(type1);
...
}
template<class P>
void Foo<P>::doSomethingElse()
{
...
TypeN typen; // There I want to instanciate a namespace1::TypeN !!
...
}
...
Of course I don't want to specialize the template and provide a dedicated implementation for every possible P value as well as I'd like to avoid passing all the types like Type1 and TypeN as template parameters since I potentially have lots of them.
Is that possible ?
The project is C++3 based, any boost solution is welcome.
Update
Being the template parameter P itself exactly like any TypeN parameter, this could be the right approach :
template<typename NAMESPACE>
class Foo
{
typedef typename NAMESPACE::Parameter MyParameter;
typedef typename NAMESPACE::Type1 MyType1;
typedef typename NAMESPACE::Type1 MyTypeN;
...
}
Yes and No.
Yes it is possible to deduce secondary types from a primary one, generally using a trait system:
template <typename T> struct Trait { typedef typename T::Secondary Secondary; };
template <typename X>
struct Foo {
typedef typename Trait<X>::Secondary Secondary;
void foo(Secondary const& s);
};
No, you cannot deduce a namespace, and thus cannot use it; but note how by using a local alias (typedef ...) within the class there is no need to.
If you are willing to add a structure inside each namespace that lists all the types you need, you can then rely on ADL to get this structure depending on a template parameter:
#include <iostream>
#include <utility>
namespace Foo_ns
{
struct T1
{
static void m() { std::cout << "Foo_ns::T1" << '\n'; }
};
struct Foo {};
// List of all the types you need from this namespace
struct Types
{
typedef Foo_ns::T1 T1;
};
// dummy function needed for ADL
Types types(...);
}
namespace Bar_ns
{
struct T1
{
static void m() { std::cout << "Bar_ns::T1" << '\n'; }
};
struct Bar {};
struct Types
{
typedef Bar_ns::T1 T1;
};
Types types(...);
}
template <typename T>
void callMOnT1(const T &arg)
{
typedef decltype(types(std::declval<T>())) Types; // ADL kicks in
//typedef typename std::result_of<types(T)>::type Types;
Types::T1::m();
}
int main()
{
callMOnT1((Bar_ns::Bar())); // Bar_ns::T1
callMOnT1((Foo_ns::Foo())); // Foo_ns::T1
}
Unfortunately, this solution using some C++11 features (namely decltype and declval). For some reason, I didn't manage to get the code working with result_of, which is present in Boost (perhaps someone could explain why the code with result_of does not compile?).
No that is impossible,but you can use ugly macro file.
//my_class.inl
template<TYPE_ARG>
struct my_class_t<TYPE_ARG>
{
foo()
{
NS_ARG::bar();
}
}
//my.h
template<class T>
struct my_class_t{};
#define TYPE_ARG T1
#define NS_ARG std
#include "my_class.inl"
#define TYPE_ARG T2
#define NS_ARG boost
#include "my_class.inl"
#undef TYPE_ARG
#undef NS_ARG
That way you will automate class specialisation for different namespaces. Do you really need this? :o)

SFINAE: Compiler doesn't pick the specialized template class

I have an SFINAE problem:
In the following code, I want the C++ compiler to pick the specialized functor and print "special", but it's printing "general" instead.
#include <iostream>
#include <vector>
template<class T, class V = void>
struct Functor {
void operator()() const {
std::cerr << "general" << std::endl;
}
};
template<class T>
struct Functor<T, typename T::Vec> {
void operator()() const {
std::cerr << "special" << std::endl;
}
};
struct Foo {
typedef std::vector<int> Vec;
};
int main() {
Functor<Foo> ac;
ac();
}
How can I fix it so that the specialized struct is used automatically? Note I don't want to directly specialize the Functor struct on Foo, but I want to specialize it on all types that have a Vec type.
P.S.: I am using g++ 4.4.4
Sorry for misleading you in the last answer, I thought for a moment that it would be simpler. So I will try to provide a complete solution here. The general approach to solve this type of problems is to write a traits helper template and use it together with enable_if (either C++11, boost or manual implementation) to decide a class specialization:
Trait
A simple approach, not necessarily the best, but simple to write would be:
template <typename T>
struct has_nested_Vec {
typedef char yes;
typedef char (&no)[2];
template <typename U>
static yes test( typename U::Vec* p );
template <typename U>
static no test( ... );
static const bool value = sizeof( test<T>(0) ) == sizeof(yes);
};
The approach is simple, provide two template functions, that return types of different sizes. One of which takes the nested Vec type and the other takes ellipsis. For all those types that have a nested Vec the first overload is a better match (ellipsis is the worst match for any type). For those types that don't have a nested Vec SFINAE will discard that overload and the only option left will be the ellipsis. So now we have a trait to ask whether any type has a nested Vec type.
Enable if
You can use this from any library, or you can roll your own, it is quite simple:
template <bool state, typename T = void>
struct enable_if {};
template <typename T>
struct enable_if<true,T> {
typedef T type;
};
When the first argument is false, the base template is the only option, and that does not have a nested type, if the condition is true, then enable_if has a nested type that we can use with SFINAE.
Implementation
Now we need to provide the template and the specialization that will use SFINAE for only those types with a nested Vec:
template<class T, class V = void>
struct Functor {
void operator()() const {
std::cerr << "general" << std::endl;
}
};
template<class T>
struct Functor<T, typename enable_if<has_nested_Vec<T>::value>::type > {
void operator()() const {
std::cerr << "special" << std::endl;
}
};
Whenever we instantiate Functor with a type, the compiler will try to use the specialization, which will in turn instantiate has_nested_Vec and obtain a truth value, passed to enable_if. For those types for which the value is false, enable_if does not have a nested type type, so the specialization will be discarded in SFINAE and the base template will be used.
Your particular case
In your particular case, where it seems that you don't really need to specialize the whole type but just the operator, you can mix the three elements into a single one: a Functor that dispatches to one of two internal templated functions based on the presence of Vec, removing the need for enable_if and the traits class:
template <typename T>
class Functor {
template <typename U>
void op_impl( typename U::Vec* p ) const {
std::cout << "specialized";
}
template <typename U>
void op_impl( ... ) const {
std::cout << "general";
}
public:
void operator()() const {
op_impl<T>(0);
}
};
Even though this is an old question, I think it's still worth providing a couple more alternatives for quickly fixing the original code.
Basically, the problem is not with the use of SFINAE (that part is fine, actually), but with the matching of the default parameter in the primary template (void) to the argument supplied in the partial specialization(typename T::Vec). Because of the default parameter in the primary template, Functor<Foo> actually means Functor<Foo, void>. When the compiler tries to instantiate that using the specialization, it tries to match the two arguments with the ones in the specialization and fails, as void cannot be substituted for std::vector<int>. It then falls back to instantiating using the primary template.
So, the quickest fix, which assumes all your Vecs are std::vector<int>s, is to replace the line
template<class T, class V = void>
with this
template<class T, class E = std::vector<int>>
The specialization will now be used, because the arguments will match. Simple, but too limiting. Clearly, we need to better control the type of the argument in the specialization, in order to make it match something that we can specify as the default parameter in the primary template. One quick solution that doesn't require defining new traits is this:
#include <iostream>
#include <vector>
#include <type_traits>
template<class T, class E = std::true_type>
struct Functor {
void operator()() const {
std::cerr << "general" << std::endl;
}
};
template<class T>
struct Functor<T, typename std::is_reference<typename T::Vec&>::type> {
void operator()() const {
std::cerr << "special" << std::endl;
}
};
struct Foo {
typedef std::vector<int> Vec;
};
int main() {
Functor<Foo> ac;
ac();
}
This will work for any Vec type that could make sense here, including fundamental types and arrays, for example, and references or pointers to them.
Another alternative for detecting the existence of a member type is to use void_t. As valid partial specialisations are preferable to the general implementation as long as they match the default parameter(s), we want a type that evaluates to void when valid, and is only valid when the specified member exists; this type is commonly (and, as of C++17, canonically) known as void_t.
template<class...>
using void_t = void;
If your compiler doesn't properly support it (in early C++14 compilers, unused parameters in alias templates weren't guaranteed to ensure SFINAE, breaking the above void_t), a workaround is available.
template<typename... Ts> struct make_void { typedef void type; };
template<typename... Ts> using void_t = typename make_void<Ts...>::type;
As of C++17, void_t is available in the utilities library, in type_traits.
#include <iostream>
#include <vector>
#include <type_traits> // For void_t.
template<class T, class V = void>
struct Functor {
void operator()() const {
std::cerr << "general" << std::endl;
}
};
// Use void_t here.
template<class T>
struct Functor<T, std::void_t<typename T::Vec>> {
void operator()() const {
std::cerr << "special" << std::endl;
}
};
struct Foo {
typedef std::vector<int> Vec;
};
int main() {
Functor<Foo> ac;
ac();
}
With this, the output is special, as intended.
In this case, since we're checking for the existence of a member type, the process is very simple; it can be done without expression SFINAE or the type_traits library, allowing us to rewrite the check to use C++03 facilities if necessary.
// void_t:
// Place above Functor's definition.
template<typename T> struct void_t { typedef void type; };
// ...
template<class T>
struct Functor<T, typename void_t<typename T::Vec>::type> {
void operator()() const {
std::cerr << "special" << std::endl;
}
};
To my knowledge, this should work on most, if not all, SFINAE-capable C++03-, C++11-, C++14-, or C++1z-compliant compilers. This can be useful when dealing with compilers that lag behind the standard a bit, or when compiling for platforms that don't have C++11-compatible compilers yet.
For more information on void_t, see cppreference.