Grz*_*icz 17 c++ boost c++11 nim-lang
我试图在C++中模拟一种与Nim编程语言不同的类型.以下示例将不在Nim中编译,因为编译器捕获变量并
具有不同的类型(),尽管两者都是二进制级别的浮点数:edError: type mismatch: got (Euros, float)
type
Euros = distinct float
when isMainModule:
var
e = Euros(12.34)
d = 23.3
echo (e + d)
Run Code Online (Sandbox Code Playgroud)
在C++中执行此操作的一种方法是为浮点数编写包装类.但是这对于导出类型的API不适用,因为它的大小与float不同.或者即使类的大小与浮点数的存储长度匹配,它也永远不会匹配char类型的大小.如果您还为加法,减法等操作实现所有可能的运算符,那么这将起作用,但需要大量输入和复制代码.
诸如创建新原始类型之类的旧问题 具有使用boost的强类型定义的可接受答案.但是,typedef似乎只适用于函数类型签名,typedef不会阻止两个float-inherited类型一起添加并且它们的类型完全改变(好吧,因为只有新类型的错觉):
#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);
}
Run Code Online (Sandbox Code Playgroud)
但这几乎就是这样,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;
}
Run Code Online (Sandbox Code Playgroud)
我正在尝试使用最新的Xcode 5.1.1在MacOSX下使用命令行编译它:
$ 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.
Run Code Online (Sandbox Code Playgroud)
也许幻灯片中给出的例子我错过了一些代码?有人有Bjarne试图展示的完整例子吗?
Pup*_*ppy 16
C++ 11中没有强大的typedef.有单位的支持,<chrono>但这是完全不同的事情.没有人能够就强大的typedef应该具有什么样的行为达成一致,所以从来没有一个关于它们的提议在任何地方都有,所以不仅它们既不是C++ 11也不是C++ 14,没有现实的前景他们将进入任何未来标准的时间.
有多种方法可以解决这个问题,但由于我正在寻找对演示幻灯片中 Bjarne 代码的修复,我接受 @robson3.14 在问题评论中留下的答案:
\n\n#include <iostream>\n\ntemplate<int M, int K, int S> struct Unit { // a unit in the MKS system\n enum { m=M, kg=K, s=S };\n};\n\ntemplate<typename Unit> // a magnitude with a unit\nstruct Value {\n double val; // the magnitude\n // construct a Value from a double\n constexpr explicit Value(double d) : val(d) {} \n};\n\nusing Meter = Unit<1,0,0>; // unit: meter\nusing Second = Unit<0,0,1>; // unit: sec\nusing Speed = Value<Unit<1,0,-1>>; // meters/second type\n\n// a f-p literal suffixed by \xe2\x80\x98_s\xe2\x80\x99\nconstexpr Value<Second> operator "" _s(long double d)\n{\n return Value<Second> (d);\n}\n// a f-p literal suffixed by \xe2\x80\x98_m\xe2\x80\x99\nconstexpr Value<Meter> operator "" _m(long double d)\n{\n return Value<Meter> (d);\n}\n// an integral literal suffixed by \xe2\x80\x98_m\xe2\x80\x99\nconstexpr Value<Meter> operator "" _m(unsigned long long d)\n{\n return Value<Meter> (d);\n}\n\ntemplate<int m1, int k1, int s1, int m2, int k2, int s2>\nValue<Unit<m1 - m2, k1 - k2, s1 - s2>> operator / (Value<Unit<m1, k1, s1>> a, Value<Unit<m2, k2, s2>> b)\n{\n return Value<Unit<m1 - m2, k1 - k2, s1 - s2>>(a.val / b.val);\n}\n\nint main()\n{\n Speed sp1 = 100_m / 9.8_s;\n std::cout << sp1.val;\n}\nRun Code Online (Sandbox Code Playgroud)\n
不确定这是你想要的,它是丑陋的,但它的工作原理:)你可以将类型包装到模板类中,
template <typename T, int N> // N is used for tagging
struct strong_typedef
{
using strong_type = strong_typedef<T,N>; // typedef for the strong type
using type = T; // the wrapped type
T value; // the wrapped value
strong_typedef(T val): value(val){}; // constructor
strong_typedef(){value={};}; // default, zero-initialization
// operator overloading, basic example:
strong_type& operator+(const strong_type& rhs)
{
value+=rhs.value;
return *this;
}
// display it
friend ostream& operator<<(ostream & lhs, const strong_typedef& rhs)
{
lhs << rhs.value;
return lhs;
}
};
Run Code Online (Sandbox Code Playgroud)
然后用它作为
// these are all different types
strong_typedef<double, 0> x = 1.1;
strong_typedef<double, 1> y = 2.2;
strong_typedef<double, 2> z = 3.3;
std::cout << x + x << std::endl; // outputs 2.2, can add x and x
// cout << x + y << endl; // compile-time ERROR, different types
Run Code Online (Sandbox Code Playgroud)
x,y和z3种不同类型的现在,因为不同的N模板使用-s.您可以使用字段访问类型和值type和value,像x::value(将双1.1).当然,如果你是直接typedef的struct_typedef::type,你就会回到正方形,因为你正在失去strong类型.所以基本上你的类型应该是,strong_typedef而不是strong_typedef::type.
| 归档时间: |
|
| 查看次数: |
6692 次 |
| 最近记录: |