【问题标题】:How To Convert Templated Function Overloads to Partial-Specialized Templated Class Static Methods?如何将模板化函数重载转换为部分专用的模板化类静态方法?
【发布时间】:2013-02-27 14:52:33
【问题描述】:

我有几个我想根据类型质量专门化的函数,例如“字符、有符号整数、无符号整数、浮点数、指针”;使用 type_traits 似乎是 the 方法,并且具有类似于以下的代码:

#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() );
}

除了在我的真实代码中,我还有barbaz等,还有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() );
}

注意:在我的真实代码中,我会使用 barbaz 等,以及 foo 静态方法。

仅供参考,这是 C++03。

顺便说一句,我是否以传统方式进行模板化函数重载?

【问题讨论】:

  • 我不明白为什么function_overload_foo() 是“指定模板类型的关键”。你在那里什么都没做,只是转发
  • 是的,我也是这么认为的,但是我的编译器 'gcc-4.7' 没有它就会抱怨:错误:没有匹配函数调用 'foo_impl(const int&)' 注意:候选人是:注意:模板 void foo_impl(const typename enable_if<:tr1::is_integral>::value, T>::type&) 注意:模板参数推导/替换失败:注意:无法推导模板参数'T ' 注意:模板 void foo_impl(const typename enable_if<:tr1::is_floating_point>::value, T>::type&) 注意:模板参数推导/替换失败:注意:无法推导模板参数'T'
  • @AndyProwl:如果您不提及模板参数,编译器无法从函数参数中推断出它,因为它是不可推断的上下文。 See this to know why it is non-deducible
  • @Nawaz:当然。我只是把整本书读得太肤浅了。谢谢。

标签: c++ templates static-methods sfinae partial-specialization


【解决方案1】:

这是一种方法:

#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;
}

【讨论】:

  • 您的答案有效,像我尝试的那样使用标签,并将所有 type_traits 检查隔离到TypeTag。然而,整个结构对我来说似乎比必要的复杂,所以在阅读了这里的答案之后,我能够改进我原来的方法,根本不依赖标签。我将代码和解释作为单独的答案发布。
【解决方案2】:

在观察了沃恩的正确答案之后,我想进一步简化它。我能够删除标签和额外的特征类的使用来提出以下结构:

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 失败时,整个部分专业化无法匹配。

相对而言,我觉得理解起来不那么麻烦。

【讨论】:

  • 事实证明,在阅读 Question 7776448 之后,我能够进一步完善我的答案,我使用 std::integral_constant 和那些直接通过 type_traits 的 "::type" 成员获得。
【解决方案3】:

enable_if 中的IntegralTypeTag 会妨碍您。 Foo的第二个参数默认是void,和IntegralTypeTag不一样,所以Foo的特化会匹配失败。

即,Foo&lt; int, void &gt;(这是您在执行 Foo&lt;int&gt; 时得到的)与您预期的 int 特化是(在 enable_if 逻辑之后)的 Foo&lt; int, IntegralTypeTag &gt; 不匹配。

标记是 type_traits 类的结果,然后您可以使用它来简化其他 type_traits 类。

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 2014-10-01
    • 1970-01-01
    • 1970-01-01
    • 2016-09-12
    • 1970-01-01
    • 1970-01-01
    • 2015-02-18
    • 1970-01-01
    相关资源
    最近更新 更多