【发布时间】:2016-07-29 01:41:15
【问题描述】:
我想为double 的不同含义添加编译时检查。在现实世界中,我试图确保所有计算都以一致的单位完成。出于这个问题的目的,我编造了一个数字有味道的玩具示例。
我一直在尝试基于模板参数来实现这一点。使用another answer 中描述的c++0x 别名功能,我将Number<Flavor> 声明为:
enum Flavor { Cherry, Plum, Raspberry };
template <Flavor> using Number = double;
这使我能够将局部变量或参数声明为特殊类型的 Number,然后在大多数情况下将这些变量用作普通双精度数。
我的问题是,我找不到一种方法来声明一个只接受特定风格作为其参数的函数:
void printCherryNumber(Number<Cherry> num) { cout << num << endl; }
int main() {
Number<Cherry> a(5);
Number<Plum> b(6);
Number<Raspberry> c(3.1415);
printCherryNumber(a);
printCherryNumber(b); // O, if only this could be a compiler error.
return 0;
}
我的目标是使printCherryNumber(b) 无法编译,因为b 是Number<Plum> 而不是Number<Cherry>。许多现有问题解决了这个问题的变体,解决方案似乎不适用于我用于Number 的类型别名构造。
我尝试过的东西
来自this answer,我看到了添加模板版本的函数的建议,该版本明确不执行任何操作或中断,如
template <typename T> void printCherryNumber(T num) = delete;
这根本没有影响,为什么要这样做? Number<Plum> 真的是 double 和 Number<Cherry> 也是 double 所以编译器从不打扰模板版本。
Another answer 建议使用单个模板函数和静态断言,如:
template <Flavor F> void printPlumNumber(Number<F> num) {
static_assert(F == Plum, "Wrong number flavor!");
cout << num << endl;
}
这失败了,因为不管F 的实际值如何,Number<F> 仍然只是double,所以我收到一个错误,提示我无法推断F 的值。
在其他地方有人suggests explicit specialization,在这种情况下也失败了:
template <Flavor F> void printRaspberryNumber(Number<F> num) = delete;
template <> void printRaspberryNumber<Raspberry>(Number<Raspberry> num) {
cout << num << endl;
}
在这里,编译器将调用视为不明确的,部分原因是它无法推断出F 的值。
房间里的大象
当然,我可以将Number 设为
template <Flavor> struct Number { double value; };
但是我试图避免这个选项,因为我对在我的代码中到处都有.value 的想法并不感到非常兴奋,我也不是特别渴望为Number 定义仅代理的运算符加倍。
强制性ideone
【问题讨论】: