我试图在 C++ 中模拟与Nim 编程语言不同的类型。以下示例不会在 Nim 中编译,因为编译器会捕获变量并
具有不同的类型 ( ),尽管它们都是二进制级别的浮点数:e
d
Error: type mismatch: got (Euros, float)
type
Euros = distinct float
when isMainModule:
var
e = Euros(12.34)
d = 23.3
echo (e + d)
在 C++ 中执行此操作的一种方法是为浮点数编写一个包装类。但这不适用于导出类型的 API,因为大小与浮点数不同。或者即使一个类的大小与浮点数的存储长度相匹配,它也永远不会与 char 类型的大小相匹配。如果您还为加法、减法等操作实现所有可能的运算符,这将起作用,但需要大量输入和重复代码。
诸如创建新的原始类型之类的较旧问题 已作为使用 boost 的强 typedef 的公认答案。然而 typedef 似乎只适用于函数类型签名, typedef 不会阻止将两个浮点继承类型添加在一起并且它们的类型完全改变(嗯,因为只是一种新类型的错觉):
#include <boost/serialization/strong_typedef.hpp>
#include <stdio.h>
BOOST_STRONG_TYPEDEF(float, money);
void test(money a, float b)
{
int t = a + b;
printf("value is %d", t);
}
int main()
{
money a(5.5);
int euros(5);
// This is not caught!
int dollars = a + euros;
printf("dollars %d\n", dollars);
// But the compiler catches this misuse.
test(euros, a);
}
但这差不多了,test()
调用将不起作用,因为签名不匹配,但是该语言仍然允许其他操作随意破坏类型。
同样的答案提到 C++0x 带来了强大的 typedef,所以我寻找这个新的支持,发现Bjarne Stroustrup 本人在 2012 年发表了 C++11 风格的主题演讲。大约在第 21 分钟,他开始谈论这些新的强类型定义。如果您只下载幻灯片,第 19 页开始讨论SI 单位,稍后第 22 页和第 23 页提到如何做到这一点。但是,我无法使这些示例正常工作。这是我设法编造的拼凑而成:
template<int M, int K, int S> struct Unit { // a unit in the MKS system
enum { m=M, kg=K, s=S };
};
template<typename Unit> // a magnitude with a unit
struct Value {
double val; // the magnitude
explicit Value(double d) : val(d) {} // construct a Value from a double
};
using Meter = Unit<1,0,0>; // unit: meter
using Second = Unit<0,0,1>; // unit: sec
using Speed = Value< Unit<1,0,-1> >; // meters/second type
constexpr Value<Second> operator "" _s(long double d)
// a f-p literal suffixed by ‘_s’
{
return Value<Second> (d);
}
constexpr Value<Meter> operator "" _m(long double d)
// a f-p literal suffixed by ‘_m’
{
return Value<Meter> (d);
}
int main(void)
{
Speed sp1 = 100_m / 9.8_s;
return 42;
}
我正在尝试在 MacOSX 下使用最新的 Xcode 5.1.1 使用命令行编译它:
$ g++ unit.cpp -std=c++11
unit.cpp:13:25: error: constexpr function's return type 'Value<Second>' is not a
literal type
constexpr Value<Second> operator "" _s(long double d)
^
unit.cpp:5:8: note: 'Value<Unit<0, 0, 1> >' is not literal because it is not an
aggregate and has no constexpr constructors other than copy or move
constructors
struct Value {
^
unit.cpp:18:24: error: constexpr function's return type 'Value<Meter>' is not a
literal type
constexpr Value<Meter> operator "" _m(long double d)
^
unit.cpp:5:8: note: 'Value<Unit<1, 0, 0> >' is not literal because it is not an
aggregate and has no constexpr constructors other than copy or move
constructors
struct Value {
^
unit.cpp:26:20: error: no matching literal operator for call to 'operator "" _m'
with argument of type 'unsigned long long' or 'const char *', and no
matching literal operator template
Speed sp1 = 100_m / 9.8_s;
^
unit.cpp:26:28: error: no matching literal operator for call to 'operator "" _s'
with argument of type 'long double' or 'const char *', and no matching
literal operator template
Speed sp1 = 100_m / 9.8_s;
^
4 errors generated.
也许幻灯片中给出的例子,我错过了更多的代码?有人有一个完整的例子来说明 Bjarne 试图展示的内容吗?