如何防止模板化别名的隐式值保留转换
How to prevent implicit value-preserving conversion of a templated alias?
我想为double
的不同含义添加编译时检查。在现实世界中,我试图确保所有的计算都是以一致的单位进行的。为了这个问题的目的,我制作了一个玩具示例,其中数字有味道。
我一直在尝试基于模板参数来实现这一点。使用另一个答案中描述的c++0x别名特性,我将Number<Flavor>
声明为:
enum Flavor { Cherry, Plum, Raspberry };
template <Flavor> using Number = double;
这使我能够将局部变量或参数声明为Number的特定风格,然后在大多数上下文中将这些变量用作普通的Double。
我的问题是,我找不到一种方法来声明一个只接受特定风格作为参数的函数:
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
中使用的类型别名构造。
我试过的东西
从这个答案中,我看到了添加该函数的模板化版本的建议,该版本显式地不执行任何操作或中断,如
template <typename T> void printCherryNumber(T num) = delete;
这根本没有效果,为什么要这样做?Number<Plum>
实际上是double
,而Number<Cherry>
也是double
,所以编译器从不为模板化版本而烦恼。
另一个答案建议使用单个模板化函数和静态断言,如:
template <Flavor F> void printPlumNumber(Number<F> num) {
static_assert(F == Plum, "Wrong number flavor!");
cout << num << endl;
}
这失败了,因为无论F
的实际值如何,Number<F>
仍然只是double
,因此我得到了一个无法推断F
的值的错误。
在其他地方,有人建议明确的专业化,但在这种情况下也失败了:
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
定义只代理到两倍的运算符。
强制性表意文字
http://ideone.com/4HiYtI
这种方法的问题:
enum Flavor { Cherry, Plum, Raspberry };
template <Flavor> using Number = double;
别名模板是透明的。Number<Cherry>
、Number<Plum>
和double
都是相同的类型。那根本不能解决你的问题。
您想要的通常被称为不透明typedef。你真的想要你的最后一个选择:
template <Flavor>
struct Number {
double value;
operator double() const { return value; } // for convenience
Number& operator=(double ); // if necessary
// possibly more operations
};
这样,Number<Cherry>
和Number<Plum>
是不同的类型。它们不能相互转换。并且CCD_ 25不能隐式地转换为任何一个。
您还可以看看BOOST_STRONG_TYPEDEF
及其实现,它也旨在解决这个问题。
您试图避免的选项实际上是实现这一点的唯一方法。
模板别名就是它本身:别名。模板别名等效于基础类型。在各个方面。
template <Flavor> using Number = double;
这意味着CCD_ 27是CCD_。这不是别的。Number<Plum>
也是double
。这与对double
进行全局搜索/替换几乎相同。最终结果将完全相同。类型完全相同。
您只能"声明一个只接受"特定类型的函数。除了使用模板别名外,模板别名是相同的类型,因此不能声明接受double
但不接受double
的函数。这是一个逻辑错误。
将double
封装在struct
中是实现这种严格类型检查的唯一方法。没那么糟糕。加入几个重载、几个operator
和封装的struct
将强制执行严格的类型检查,编译器可能会生成相同的代码,而不会在运行时受到惩罚。
- 防止主数据类型C++的隐式转换
- 模板参数替换失败,并且未完成隐式转换
- 努力将整数转换为链表。不知道我在这里做错了什么
- HEX值到wchar_t字符(UTF-8)的转换
- lambda参数转换为constexpr技巧,然后获取带链接的数组
- 将 Qvector<uint8_t> 转换为 QString
- 如何在cuSparse中使用cusparseXcoo2csr从coo转换为csc
- 有关插入适配器的错误。[错误]请求从 'back_insert_iterator<vector<>>' 类型转换为非标量类型
- 是否有内置方法可以强制转换为不同的基础类型,但保留常量限定符?
- Qt 将字符串转换为以 16 为基数的 int,但保留以 16 为基数的值
- 如何将STD :: String转换为QString保留值,反之亦然
- 如何将浮点数转换为保留位值的整数
- C++Cout将字符串转换为保留所有小数的十进制数
- OpenCL:减少示例,并保留内存对象/将cuda代码转换为OpenCL
- 如何在小数点后保留0,将字符串转换为双精度
- 将double/float类型转换为string类型,保留科学记数法和精度
- 如何防止模板化别名的隐式值保留转换
- 在 C++ 中,从无符号 int 到 int 的转换始终保留位模式
- 从 Iplimage 转换为 Mat 不会保留深度信息
- 当将透明png图像转换为位图时,它不会保留透明度