#include <type_traits>
struct Mipmaptable { virtual ~Mipmaptable() {} /* ... */ } ;
// is T derived from Mipmapable?
template < typename T > // http://en.cppreference.com/w/cpp/header/type_traitsstruct is_mipmapable : std::conditional< std::is_base_of<Mipmaptable,T>::value,
std::true_type, std::false_type >::type {} ;
// T could be anything
template < typename T, typename = void > class MipMap ; // not defined
// T must be derived from Mipmaptable
template < typename T > // http://en.cppreference.com/w/cpp/types/enable_ifclass MipMap< T, typename std::enable_if< is_mipmapable<T>::value, void >::type >
{
// ...
};
int main()
{
struct A : Mipmaptable { /* ... */ };
MipMap<A> mma ; // fine: A is derived from Mipmaptable
// MipMap<A> is defined (specialization)
MipMap<int> mmi ; // *** error: int is not derived from Mipmaptable
// MipMap<int> is an incomplete type (generalization)
}
If there is.no useful functionality for other T, this can also be done with a static_assert in the body of MipMap (which has the benefit of more explicit compiler diagnostic.
#pragma once
template <typename T>
class Mipmapable // A class deriving from this class can create MipMaps of class T
{
public:
virtual ~Mipmapable() {}
virtual T* makeMipMap();
};
leading to error:
1>main.obj : error LNK2001: unresolved external symbol "public: virtual class ByteMap * __thiscall Mipmapable<class ByteMap>::makeMipMap(void)" (?makeMipMap@?$Mipmapable@VByteMap@@@@UAEPAVByteMap@@XZ)
1>main.obj : error LNK2001: unresolved external symbol "public: virtual class ColorIndexMap * __thiscall Mipmapable<class ColorIndexMap>::makeMipMap(void)" (?makeMipMap@?$Mipmapable@VColorIndexMap@@@@UAEPAVColorIndexMap@@XZ)
For clarification, MipMap is sort of a dual paradigm in Computer Graphics terminology: It can basically mean a single image as well as multiple images belonging together. See https://en.wikipedia.org/wiki/Mipmap for nice self-explanatory image.
#include <type_traits>
template < typename T >
struct Mipmaptable
{
virtual ~Mipmaptable() {}
virtual T* makeMipMap() const = 0 ; // pure
// ...
} ;
// is T derived from Mipmaptable<T>?
template < typename T > // http://en.cppreference.com/w/cpp/header/type_traitsstruct is_mipmapable : std::conditional< std::is_base_of<Mipmaptable<T>,T>::value,
std::true_type, std::false_type >::type {} ;
// T could be anything
template < typename T, typename = void > class MipMap ; // not defined
// T must be derived from Mipmaptable
template < typename T > // http://en.cppreference.com/w/cpp/types/enable_ifclass MipMap< T, typename std::enable_if< is_mipmapable<T>::value, void >::type >
{
// ...
};
// T could be anything
template < typename T, typename = void > class MipMap_Cubbi // Cubbi's idea
{
// compile-time assertion: T must be derived from Mipmaptable<T>
static_assert( is_mipmapable<T>::value, "T must be derived from Mipmaptable<T>" ) ;
};
// IIRC, VC++ 2010 does not support local types as template arguments
struct A : Mipmaptable<A>
{
// VC++ 2010 does not support the override specifier
virtual A* makeMipMap() const /*override*/ { returnnew A ; }
// ...
};
int main()
{
MipMap<A> mma ; // fine: A is derived from Mipmaptable<A>
// MipMap<A> is defined (specialization)
MipMap_Cubbi<A> mmca ; // fine: A is derived from Mipmaptable<A>
// the compile-time assertion holds
MipMap_Cubbi<int> mmci ; // error: static assertion failed:
// T must be derived from Mipmaptable<T>
}