Reputation: 877
I'm started playing around with templates and came accross a problem with a need to call a function based on 2 template parameter types. I'm writting simple unit library that will have helper getConvertionFactor
functions that will define ratio between units. I'd like to be able to pickup a function in template operators +,-,*,/ defintion based on types beeing pased as arguments. I know it's possible when these arguments are passed futher to getConvertionFactor
function. Then overload resolution will pickup function that has specified ratio between given arguments type. But this approach as I undestand will result with unnecessary copying of LHS and RHS parameters into getConvertionFactor
function just to perform overload resolution. I'd like to avoid it and perform somehow lookup of a function based on 2 types without need to pass dummy
parameters into it.
#include <iostream>
struct Kilometer {
int val = 0;
};
struct NauticalMile {
int val = 0;
};
template<class FromType, class ToType>
double getConvertionFactor() {
return FromType::getBaseValue();
}
// How to define such conceptually function pointer lookup based on these 2 types?
// double getConvertionFactor<Kilometer, NauticalMile>() {
// return 0.1;
// }
// Works but requires copying parameters
double getConvertionFactor(Kilometer km, NauticalMile /*nm*/) {
return 0.1 * km.val;
}
template<class LHS_Unit, class RHS_Unit>
LHS_Unit operator+(const LHS_Unit& nm, const RHS_Unit& km) {
LHS_Unit lhs;
lhs.val = nm.val + getConvertionFactor(nm, km)*km.val;
return lhs;
}
int main() {
Kilometer km{100};
NauticalMile nm{100};
auto res = km + nm;
std::cout << res.val << std::endl;
return 0;
}
Upvotes: 0
Views: 857
Reputation: 85371
You can do it like this:
template<class FromType, class ToType>
double getConvertionFactor() {
return 1;
}
template<>
double getConvertionFactor<Kilometer, NauticalMile>() {
return 1.852;
}
template<>
double getConvertionFactor<NauticalMile, Kilometer>() {
return 1 / 1.852;
}
template<class LHS_Unit, class RHS_Unit>
LHS_Unit operator+(const LHS_Unit& lhs, const RHS_Unit& rhs) {
return { lhs.val + getConvertionFactor<LHS_Unit, RHS_Unit>() * rhs.val };
}
But it might be a good idea to implement user-defined conversion operators so that the types are implicitly convertible to one another.
#include <iostream>
struct Kilometer;
struct NauticalMile;
struct Kilometer {
double val = 0;
operator NauticalMile() const;
};
struct NauticalMile {
double val = 0;
operator Kilometer() const;
};
Kilometer::operator NauticalMile() const {
return { val / 1.852 };
}
NauticalMile::operator Kilometer() const {
return { val * 1.852 };
}
template<class LHS_Unit, class RHS_Unit>
LHS_Unit operator+(const LHS_Unit& lhs, const RHS_Unit& rhs) {
return { lhs.val + static_cast<LHS_Unit>(rhs).val };
}
int main() {
Kilometer km{ 100 };
NauticalMile nm{ 100 };
auto res = km + nm;
std::cout << res.val << std::endl;
return 0;
}
Upvotes: 1