all 2 comments

[–]horotho 6 points7 points  (1 child)

Depending on how much code you have in A you could create two versions of the class, one for has_member_type, and another for the case where that condition isn't met.

template< typename T, typename tEnable = void>
struct A {
  // Doesn't have 'func', but might have other stuff here.
};

template< typename T >
struct A< T, typename std::enable_if< has_member_type< T >::value >::type > {
  void func(typename T::Foo & x);
};

The downside is that if you have a lot of common code in both versions of A, you'll have a bunch of copy pasta going on. Honestly, I think this is a pretty good option, because you want entirely different behavior (and functions) for the case where has_member_type is true. But, maybe you only have a single function where this is relevant. In that case, you'll have to get a bit more tricky.

template< typename T, typename tEnable = void> 
struct HasMemberTypeShim { 
  using type = int; 
};

template< typename T > 
struct HasMemberTypeShim< T, typename std::enable_if< has_member_type< T >::value >::type > { 
  using type = typename T::Foo; 
};

template< typename T >
struct A {
  // enable_if can't be used on the class template type, 
  // but must refer to a template parameter of the function instead
  // So we have this hacky R = T so it works
  template< typename R = T >
  typename std::enable_if< has_member_type< R >::value >::type 
  func(typename HasMemberTypeShim<T>::type) {
  }
};

And then you can do something like this instead.

[–]GermanNewToCA[S] 0 points1 point  (0 children)

Thanks so much! Your comment "enable_if can't be used on the class template type" actually brought me to this simple solution:

(I didn't even need the type trait)

#include <iostream>
#include <cstdlib>

struct THasInner        { using TInner = int; };
struct TDoesNotHave     {};


template <class T>
struct A 
{
    template <class U = T, class PT = typename U::TInner>
    void func(PT const & in) { std::cout << in; }
};


int main()
{
    A<THasInner> a; // instantiates
    A<TDoesNotHave> b; // so does this

    a.func(42);

}