'Specialice template function
Consider the following template to store simplified SI units:
template < int Mass, int Length, int Time >
class TUnit
{
public:
// Used type.
typedef float DataType;
.....
}
For example SI Unit "length" is defined as follows:
typedef TUnit< 0, 1, 0 > Length;
There exits a global generic function to convert DataTypes to TUnits:
template < int Mass, int Length, int Time >
TUnit< Mass, Length, Time > convert( const typename TUnit< Mass, Length, Time >::DataType& src );
And we have a specialized version to convert float to length with e.g. an implicit conversion e.g. from [km] to [m]:
template < >
Tools::DataTypes::Length convert( const Tools::DataTypes::Length::DataType& src );
Now try to convert a float to length:
float f = 1.0;
Length l = ::convert( f )
Now VC2012 fails to compile with error code:
error C2783: could not deduce template argument for 'Mass'
could not deduce template argument for 'Length'
could not deduce template argument for 'Time'
To solve this I changed the code to:
float f = 1.0;
Length l = ::convert< 0, 1, 0 >( f )
Nice but this is not what I want :) My preferred syntax would be:
float f = 1.0;
Length l = ::convert< Length >( f )
I think I have to change the signature of the generic template function to something like this:
template < TUnit< int Mass, int Length, int Time > >
TUnit< Mass, Length, Time > convert( const typename TUnit< Mass, Length, Time >::DataType& src );
But of course this syntax is wrong. Any hints to solve this ?
Solution 1:[1]
1. Variant (via template class)
You can not specialize function templates. If you really want to do this, then make a class with a single static function and specialize that class. You can then make the function call the static method of that class.
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();
}
And then you define the template class:
template < int Mass, int Length, int Time >
struct Converter {
static TUnit< Mass, Length, Time > call( const typename TUnit< Mass, Length, Time >::DataType& src) {
[...]
}
};
And its specializations, e.g. for Length:
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. Variant Overloading
Alternatively, I would recommend to use function overloading instead, which will mostly be equivalent, with that I mean
// NOTE: no `template < >`
Tools::DataTypes::Length convert( const Tools::DataTypes::Length::DataType& src );
Due to the C++ overload mechanism this overloaded function has precedence over the function template convert<Mass, Length, Time>. That is as long as you don't call the function with explicit template arguments.
3. Variant Additional Function Template
If you want to your second approach to work, then I recommend:
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_;
[...]
And then
template < class TUnitT >
TUnitT convert( const typename TUnitT::DataType& src ) {
return convert<TUnitT::Mass, TUnitT::Length, TUnitT::Time>(src);
}
But I would recommend the first approach.
Solution 2:[2]
Sure you can use a template as a template argument. In this case it will be a specialized type so you don't even have to use the template template idiom. Just write something like this:
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 );
This will compile fine.
Sources
This article follows the attribution requirements of Stack Overflow and is licensed under CC BY-SA 3.0.
Source: Stack Overflow
| Solution | Source |
|---|---|
| Solution 1 | |
| Solution 2 |
