简体   繁体   中英

Specialize class for Base and all Derived

I have a Base-class and a derived class. I would like to design a Class C that reacts differently when a base or derived object is handed over like this:

template<typename T>
class Base {};
class Derived: public Base<int>{}

template<typename T>
class C
{
public:
    static int f(T&& arg) {return 1;};
};
// Specialize C, not the function
template<typename T>
class C<T>
{
public:
    static int f(T&& arg) {return 2;};
};

template<typename T>
int function(T&& arg) {
    return C<T>::f(std::forward<T>(arg));
}

int main()
{
    std::cout << function(1) << std::endl;
    std::cout << function(Base<float>()) << std::endl;
    std::cout << function(Derived()) << std::endl;
}

This is supposed to print:

1

2

2

Is there a way that I can do this with specializing the class C and not the function. In reality I just hand over the type C and everything happens out of my reach. To clearify, the implementation of function may look like that but I can't really tell. All I know is the signature of f: int f(T&&) ; And that I have to have a class C that has a function of that signature.

Through Specialization of function():

Example code first:

template< class T >
struct Base
{};

struct Child : Base<int>
{    };

template<typename T>
class C1
{
public:
    static int f(T&& arg) {return 1;}
};

template<typename T>
class C2
{
public:
    static int f(T&& arg) {return 2;}
};

template<typename T>
typename std::enable_if< std::is_base_of<Base<int>, T>::value, int >::type function(T&& arg) 
{
    return C2<T>::f(std::forward<T>(arg));
}

template<typename T>
typename std::enable_if< !std::is_base_of<Base<int>, T >::value, int >::type function(T&& arg) 
{
    return C1<T>::f(std::forward<T>(arg));
}

int main()
{
    std::cout << function(1) << std::endl;
    std::cout << function(Base<int>()) << std::endl;
    std::cout << function(Child()) << std::endl;
    return 0;
}

Why:

So the split here is that I've written two versions of function(). The return type of function() looks a little hairy but the first version will be compiled if T has Base< int > as a base type. Otherwise the second version will be used.

std::enable_if<> is a neat tool which causes the template expansion to fail if its condition is not met. In this case we cause the template expansion to fail if T does not have Base< int > as a base class. In the case that the template expansion fails the compiler continues to look for another version of function() which will compile.

C1 and C2 are then two different objects with C2 being used if T has Base as a child, otherwise C1 is used.

Through Specialization of C:

template< class BaseArgument >
Base< BaseArgument > get_Base_type_of( Base< BaseArgument >&& );

template< class T >
struct has_Base
{
  typedef char yes;
  typedef long no;

  template< typename T1 >
  static yes Check( decltype( get_Base_type_of( declval<T1>() ) )* );

  template< typename T1 >
  static no Check( ... );

  static const bool value = sizeof( decltype( Check<T>(0) ) ) == sizeof( yes ) ;
};

template< typename T, typename Placeholder = void >
class C
{
public:
    static int f(T&& arg) {return 1;};
};

template<typename T>
class C< T, typename std::enable_if< has_Base<T>::value >::type >
{
public:
    static int f(T&& arg) {return 2;};
};

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM