1

This is a follow up to my question SFINAE with variadic templates. I was trying to construct a variadic template named has_member for checking whether a class has a member (called member).

I tried to see if I could use size_t instead of void in the answer to that question and not use variadic templates, as follows:

#include <iostream>
#include <vector>
using namespace std;

class ClassWithMember
{
    public:
    int member;
};
class ClassWithoutMember
{
};

template <typename T,typename=size_t>
class has_member: public std::false_type
{
};
template <typename T>
class has_member<T,decltype(sizeof(typename T::member))>: public std::true_type
{
};

template <typename T1,
          std::enable_if_t<has_member<T1>::value>* = nullptr>
void my_function(const T1& obj) { cout<<"Function for classes with member"<<endl; }

template <typename T1,
          std::enable_if_t<!has_member<T1>::value>* = nullptr>
void my_function(const T1& obj) { cout<<"Function for classes without member"<<endl; }


int main()
{
    ClassWithMember objWithMember;
    ClassWithoutMember objWithoutMember;
    my_function (objWithMember);
    my_function (objWithoutMember);
}

I get no errors, but the specialization is never used. Only the function for classes without the member gets called. Could someone please explain why?

Community
  • 1
  • 1
SPMP
  • 1,181
  • 1
  • 9
  • 24

1 Answers1

1

The typename before T::member is needless.

#include <iostream>
#include <vector>
using namespace std;

class ClassWithMember
{
    public:
    int member;
};
class ClassWithoutMember
{
};

template <typename T,typename=size_t>
class has_member: public std::false_type
{
};

template <typename T>
class has_member<T,decltype(sizeof(T::member))>: public std::true_type
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~^^^^^
{
};

template <typename T1,
          std::enable_if_t<has_member<T1>::value>* = nullptr>
void my_function(const T1& obj) { cout<<"Function for classes with member"<<endl; }

template <typename T1,
          std::enable_if_t<!has_member<T1>::value>* = nullptr>
void my_function(const T1& obj) { cout<<"Function for classes without member"<<endl; }


int main()
{
    ClassWithMember objWithMember;
    ClassWithoutMember objWithoutMember;
    my_function (objWithMember);
    my_function (objWithoutMember);
}

Demo

[OT] Just a tip for further metaprogramming: you can also test by using the real types instead of templates.

Naios
  • 1,513
  • 1
  • 12
  • 26
  • It worked! Could you please add a short explanation maybe? – SPMP Sep 17 '15 at 23:04
  • It looks like there is no problem with real types. It was introduced in c++0x apparently. http://stackoverflow.com/questions/5976879/getting-the-size-of-member-variable So why is there a problem with templates? I treid out what Denis mentioned at the end of his answer, and there were no errors at all. – SPMP Sep 18 '15 at 02:53
  • Corrected it, the `typename` keyword wasn't neccessary. – Naios Sep 18 '15 at 10:52
  • It's not a dependent type i think: `error: typename specifier refers to non-type member 'member' in 'ClassWithMember'` – Naios Sep 18 '15 at 10:57
  • Hmm.. yeah. I don't see the error you mention, but member is not really a type. That explains it.. – SPMP Sep 18 '15 at 15:08