专业化模板功能

时间:2012-11-12 18:34:23

标签: c++ templates

考虑以下模板来存储简化的SI单位:

template < int Mass, int Length, int Time >
class TUnit
{
public:
    // Used type.
typedef float DataType;
    .....
}

例如SI单位“长度”定义如下:

typedef TUnit< 0, 1, 0 > Length;

有一个全局泛型函数可以将DataTypes转换为TUnits:

template < int Mass, int Length, int Time >
TUnit< Mass, Length, Time > convert( const typename TUnit< Mass, Length, Time >::DataType& src );

我们有一个专门的版本可以将浮点数转换成长度,例如隐式转换,例如从[km]到[m]:

template < >
Tools::DataTypes::Length convert( const Tools::DataTypes::Length::DataType& src );

现在尝试将float转换为length:

float f = 1.0;
Length l = ::convert( f )

现在VC2012无法编译错误代码:

error C2783: could not deduce template argument for 'Mass'
             could not deduce template argument for 'Length'
             could not deduce template argument for 'Time'

为了解决这个问题,我将代码更改为:

float f = 1.0;
Length l = ::convert< 0, 1, 0 >( f )

很好,但这不是我想要的:)我首选的语法是:

float f = 1.0;
Length l = ::convert< Length >( f )

我认为我必须将通用模板函数的签名更改为:

template < TUnit< int Mass, int Length, int Time > >
TUnit< Mass, Length, Time > convert( const typename TUnit< Mass, Length, Time >::DataType& src );

但当然这种语法是错误的。有什么提示可以解决这个问题吗?

2 个答案:

答案 0 :(得分:0)

1。变体(通过模板类)

您不能专门化功能模板。如果你真的想这样做,那么用一个静态函数创建一个类并专门化这个类。然后,您可以使该函数调用该类的静态方法。

template < int Mass, int Length, int Time >
TUnit< Mass, Length, Time > convert( const typename TUnit< Mass, Length, Time >::DataType& src ) {
  return Converter<Mass, Length, Time>::call();
}

然后定义模板类:

template < int Mass, int Length, int Time >
struct Converter {
   static TUnit< Mass, Length, Time > call( const typename TUnit< Mass, Length, Time >::DataType& src) {
     [...]
   }
};

其专长,例如长度:

template < >
struct Converter<0,1,0> {
   static const int Mass = 0;
   static const int Length = 1;
   static const int Time = 0;

   static TUnit< Mass, Length, Time > call( const typename TUnit< Mass, Length, Time >::DataType& src) {
     [...]
   }
};

2。变体重载

或者,我建议使用函数重载,这大部分都是等价的,我的意思是

// NOTE: no `template < >`
Tools::DataTypes::Length convert( const Tools::DataTypes::Length::DataType& src );

由于C ++重载机制,这个重载函数优先于函数模板convert<Mass, Length, Time>。只要您不使用显式模板参数调用该函数即可。

3。变体附加功能模板

如果你想要第二种方法,那么我建议:

template < int Mass_, int Length_, int Time_ >
class TUnit
{
public:
  static const int Mass = Mass_;
  static const int Length = Length_;
  static const int Time = Time_;
[...]

然后

template < class TUnitT >
TUnitT convert( const typename TUnitT::DataType& src ) {
  return convert<TUnitT::Mass, TUnitT::Length, TUnitT::Time>(src);
}

但我建议采用第一种方法。

答案 1 :(得分:0)

当然可以使用模板作为模板参数。在这种情况下,它将是一种专门类型,因此您甚至不必使用模板模板惯用法。写这样的东西:

template < class TUNIT>
TUNIT convert( const typename TUNIT::DataType& src );

template < int M, int A, int B>
TUnit<M,A,B> convert( const typename TUnit<M,A,B>::DataType& src )
{
    typedef TUnit< M,A,B > TUnit_;
    return ::convert<TUnit_>(src);
}

...

typedef TUnit< 0, 1, 0 > Length;

...

float f = 1.0f;
Length l = ::convert< Length >( f );

这将编译好。