У меня есть несколько функций, которые я хочу специализировать на основе качеств типов, таких как «символ, целое число со знаком, целое число без знака, с плавающей точкой, указатель»; использование type_traits кажется способ сделать это, и иметь код, подобный следующему:
#include <tr1/type_traits>
#include <iostream>
template<bool, typename _Tp = void>
struct enable_if
{ };
template<typename _Tp>
struct enable_if<true, _Tp>
{
typedef _Tp type;
};template< typename T >
inline void
foo_impl( typename enable_if< std::tr1::is_integral< T >::value, T >::type const& )
{
std::cout << "This is the function-overloaded integral implementation.\n";
}
template< typename T >
inline void
foo_impl( typename enable_if< std::tr1::is_floating_point< T >::value, T >::type const& )
{
std::cout << "This is the function-overloaded floating-point implementation.\n";
}
template< typename T >
inline void
function_overloads_foo( T const& arg )
{
foo_impl< T >( arg ); // vital to specify the template-type
}
void function_overloads_example()
{
function_overloads_foo( int() );
function_overloads_foo( float() );
}
кроме моего реального кода, у меня также есть bar
,baz
и т. д. вместе с foo
,
Тем не менее, я хотел бы сгруппировать все эти функции по качеству в один шаблонный класс как static
методы. Как это лучше всего сделать? Вот моя наивная и неудачная попытка использовать теги, SFINAE и частичную специализацию:
struct IntegralTypeTag;
struct FloatingPointTypeTag;
template< typename T, typename U = void >
class Foo
{
};
template< typename T >
class Foo< T, typename enable_if< std::tr1::is_integral< T >::value, IntegralTypeTag >::type >
{
static void foo( T const& )
{
std::cout << "This is the integral partial-specialization class implementation.\n";
}
};
template< typename T >
class Foo< T, typename enable_if< std::tr1::is_floating_point< T >::value, FloatingPointTypeTag >::type >
{
static void foo( T const& )
{
std::cout << "This is the floating-point partial-specialization class implementation.\n";
}
};
template< typename T >
inline void
partial_specialization_class_foo( T const& arg )
{
Foo< T >::foo( arg );
}
void partial_specialization_class_example()
{
partial_specialization_class_foo( int() );
partial_specialization_class_foo( float() );
}
Заметка: в моем реальном коде я бы bar
,baz
и т. д. вместе с foo
статическая-метода.
К вашему сведению, это C ++ 03.
Кроме того, я делаю перегрузку шаблонной функции обычным способом?
Вот один из подходов:
#include <tr1/type_traits>
#include <iostream>
struct IntegralTypeTag;
struct FloatingPointTypeTag;
template <
typename T,
bool is_integral = std::tr1::is_integral<T>::value,
bool is_floating_point = std::tr1::is_floating_point<T>::value
> struct TypeTag;
template <typename T>
struct TypeTag<T,true,false> {
typedef IntegralTypeTag Type;
};
template <typename T>
struct TypeTag<T,false,true> {
typedef FloatingPointTypeTag Type;
};
template <typename T,typename TypeTag = typename TypeTag<T>::Type> struct Foo;template <typename T>
struct Foo<T,IntegralTypeTag> {
static void foo( T const& )
{
std::cout << "This is the integral partial-specialization class implementation.\n";
}
};
template <typename T>
struct Foo<T,FloatingPointTypeTag> {
static void foo( T const& )
{
std::cout << "This is the floating-point partial-specialization class implementation.\n";
}
};
template< typename T >
inline void
partial_specialization_class_foo( T const& arg )
{
Foo< T >::foo( arg );
}
int main(int,char**)
{
partial_specialization_class_foo(int());
partial_specialization_class_foo(float());
return 0;
}
Наблюдая за правильным ответом Вона, я хотел еще больше упростить его. Мне удалось убрать использование тегов и дополнительных классов-трейтов, чтобы создать следующую структуру:
template< typename T, typename U = T >
struct Foo
{
};
template< typename T >
struct Foo< T, typename enable_if< std::tr1::is_integral< T >::value, T >::type >
{
static void foo( T const& )
{
std::cout << "This is the integral partial-specialization class implementation.\n";
}
};
template< typename T >
struct Foo< T, typename enable_if< std::tr1::is_floating_point< T >::value, T >::type >
{
static void foo( T const& )
{
std::cout << "This is the floating-point partial-specialization class implementation.\n";
}
};
template< typename T >
inline void
partial_specialization_class_foo( T const& arg )
{
Foo< T >::foo( arg );
}
void partial_specialization_class_example()
{
partial_specialization_class_foo( int() );
partial_specialization_class_foo( float() );
}
Я думаю, что это работает, предоставляя два параметра типа шаблона для класса, где второй является условным во время компиляции:
enable_if
терпит неудачу, вся частичная специализация недоступна для сравнения.Я нахожу это менее громоздким для понимания, сравнительно.
IntegralTypeTag
в enable_if
будет мешать. По умолчанию для второго параметра Foo
является void
, который не совпадает с IntegralTypeTag
так что специализация Foo
не сможет соответствовать.
То есть, Foo< int, void >
(что вы получаете, когда делаете Foo<int>
) не совпадает Foo< int, IntegralTypeTag >
, который вы хотели int
специализация есть (после enable_if
логика).
Пометка является результатом type_traits
класс, который вы можете использовать для упрощения других type_traits
классы.