我有一个通常返回整数的函数,但由于值的语义可能不同,我想强类型那些,所以我介绍了两种类型,例如:金钱和时间,简化为
struct Money {
uint32_t value;
}
该函数将返回Money或Time,具体取决于bool参数。让我们说它看起来像这样:
template <typename T> T getValue(bool mode) {
Money money;
Time time;
...
if (mode == ModeMoney) {
money = something * 2;//get it from somewhere - irrelevant for the example
return money;
}
if (mode == ModeTime) {
time = something * 100;
return time;
}
}
现在编译器会抱怨不同的返回类型,所以我添加了专门的模板函数来返回值本身:
template <> Money variableValue<Money>(something) { return something * 2 };
template <> Time variableValue<Time>(something) { return something * 100};
这允许在调用时删除bool param,main函数现在将更改为:
template <typename T> T getValue(bool mode) {
....//calculation of *something* is the same, we only need different output from the function
return variableValue<T>(something);
}
这是一个好方法吗?
答案 0 :(得分:2)
按照Ami的评论,我建议你做两个函数和一个帮手:
Time getTime() { return calculateSomething() * 100; }
Money getMoney() { return calculateSomething() * 2; }
将单独的用例分开;模板的主要目的是使接口更简单,而不是实现。但是,如果你使用模板将看起来应该是两个函数的东西变成一个,这不会使界面更简单,因为它不直观。 (也不是,正如你的问题所示,它实际上是否使实现变得更简单。)
答案 1 :(得分:1)
作为替代解决方案,您可以使用traits类来执行此操作并避免重复代码 它遵循一个最小的例子:
template<typename>
struct traits;
template<>
struct traits<Money> {
using return_type = Money;
static constexpr std::size factor = 2;
};
template<>
struct traits<Time> {
using return_type = Time;
static constexpr std::size factor = 100;
};
template <typename T>
traits<T>::return_type getValue() {
traits<T>::return_type ret;
// ...
ret = something * traits<T>::factor;
return ret:
}
如果它是一个合适的解决方案,主要取决于实际代码和getValue
的实际实现。
答案 2 :(得分:0)
除了关于设计问题的问题之外,您似乎想要一个标记的联合或变体variant<Time, Money>
。下一个C ++标准将有variant class in the standard library,但在此可用之前,您可以使用Boost.Variant。有了这个,代码看起来像
std::variant<Money, Time> getValue(bool mode) {
if (mode) {
return std::variant<Money, Time>( Money{23} );
}
else {
return std::variant<Money, Time>( Time{42} );
}
}
auto m = std::get<Money>( getValue(true) );
auto m2 = std::get<Money>( getValue(false) );
assert( m != nullptr && m2 == nullptr );
您也可以仅使用union实现自己的Money和Time变体:
struct TimeOrMoney
{
enum class Type {isTime, isMoney};
Type type;
union
{
Time time;
Money money;
}
}
另一种方法可能是返回std::pair< boost::optional<Money>, boost::optional<Time> >
,然后检查两者中的哪一个实际设置。这使用特殊的可选状态作为标记来指示已设置的值。