考虑以下模板来存储简化的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 );
但当然这种语法是错误的。有什么提示可以解决这个问题吗?
答案 0 :(得分:0)
您不能专门化功能模板。如果你真的想这样做,那么用一个静态函数创建一个类并专门化这个类。然后,您可以使该函数调用该类的静态方法。
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) {
[...]
}
};
或者,我建议使用函数重载,这大部分都是等价的,我的意思是
// NOTE: no `template < >`
Tools::DataTypes::Length convert( const Tools::DataTypes::Length::DataType& src );
由于C ++重载机制,这个重载函数优先于函数模板convert<Mass, Length, Time>
。只要您不使用显式模板参数调用该函数即可。
如果你想要第二种方法,那么我建议:
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 );
这将编译好。