aki*_*kim 3 c++ types stl type-safety c++14
假设我有一个代表自动机的类,其状态为编号(using state_t = unsigned),其过渡也编号(using transition_t = unsigned).当然,在某些时候我最终搞乱,因为有些电话transition_t和state_t属于同一类型,所以编译器不执行(语义)类型的安全性.通过使用由tag(struct transition_tag {}; struct state_tag {};)模板化的小类,这很容易解决,所以现在transition_t和state_t不兼容,好!
/// Lightweight state/transition handle (or index).
template <typename Tag>
struct index_t_impl
{
using index_t = unsigned;
constexpr index_t_impl(index_t i)
: s{i}
{}
// Disallow index1_t i{index2_t{42}};
template <typename T>
index_t_impl(index_t_impl<T> t) = delete;
bool operator==(index_t_impl t) const
{
return s == t.s;
}
// Disallow index1_t{42} == index2_t{42};
template <typename T>
bool operator==(index_t_impl<T> t) const = delete;
/// Default ctor to please containers.
index_t_impl() = default;
constexpr operator index_t() const { return s; }
/// Be compliant with Boost integer ranges.
index_t_impl& operator++() { ++s; return *this; }
/// Be compliant with Boost integer ranges.
index_t_impl& operator--() { --s; return *this; }
private:
index_t s;
};
Run Code Online (Sandbox Code Playgroud)
此外,我有两个非常相似的结构:
predecessors_t从过渡到其前任过渡的映射(在最短路径中).为了效率,它是一个std::vector<transition_t>.path_t是转换索引的列表.为了效率,它是一个std::vector<transition_t>.然后我再次将这个问题std::vector<transition_t>用于两个完全不同的目的.当然,我可以再次引入一个由标签模板化的包装器,但事情再次变得混乱.公共继承非常诱人(你不能继承std :: vector)!
但实际上,每次我想要引入与基本类型完全相同但又不兼容的新类型时,我已经厌倦了临时解决方案.这方面有什么建议吗?公共继承真的很有吸引力,但它不会引入额外实例化的代码膨胀吗?也许struct predecessors_t { std::vector<transition_t> v; };Crashworks推荐的公共组合()(/sf/answers/304729351/)是一个更好的选择,可以更好地扩展?
C++的未来有什么东西可以解决这个新问题吗?
获取编译器强制语义类型的问题可以在各种情况下出现,从您的情况到协调具有不同来源的系统(其中值都是相同的类型(例如,int)),但在语义上,类型必须不要混合,因为它们代表来自不同来源的偏移(x,y,z = 0,0,0) - 这在数学中经常发生,其中,当用正x和y绘制象限时,原点在较低的位置左,和计算机科学,其中将原点左上角放置在宇宙飞船导航中(更多内容见下文).
2012年,Bjarne Stroustrup就他所谓的类型丰富的编程进行了一次有趣的讨论,该编程通过使用模板,用户定义的文字,声称没有运行时开销实现甚至是课程故事的C++ 11引入了编译器强制语义类型安全性.从火星气候观察报告中了解到(由于缺乏强制语义类型安全性,耗资3.5亿美元的航天器+任务丢失).你可以在这里看到他所涉及的语义类型的部分内容:https://youtu.be/0iWb_qi2-uI?t = 19m6s
我已经根据Stroustrup的演示代码编写了一个示例代码摘录,更新为当前标准并实现了所需的运算符重载.与Bjarne的例子不同,这个实际上是编译的.;)
这段代码的要点可以在这里找到:https://gist.github.com/u-007d/361221df5f8c7f3466f0f09dc96fb1ba
//Compiled with clang -std=c++14 -Weverything -Wno-c++98-compat main.cpp -o main
#include <iostream>
#include <string>
template<int M, int K, int S> //Meters, Kilograms, Seconds (MKS)
struct Unit
{
enum { m=M, kg=K, s=S };
};
template<typename Unit> //a magnitude with a unit
struct Value
{
double val; //the magnitude
constexpr explicit Value(double d) : val(d) {} //construct a Value from a double
};
//Basic Semantic Units for MKS domain
using Meter = Unit<1, 0, 0>;
using Kilogram = Unit<0, 1, 0>;
using Second = Unit<0, 0, 1>;
using Second2 = Unit<0, 0, 2>;
//Semantic Value Types for MKS domain
using Time = Value<Second>;
using Distance = Value<Meter>;
using Mass = Value<Kilogram>;
using Speed = Value<Unit<1, 0, -1>>; //Speed is meters/second
using Acceleration = Value<Unit<1, 0, -2>>; //Acceleration is meters/second^2
//Operator overloads to properly calculate units (incomplete; for demo purposes)
Speed operator/(const Distance& lhs, const Time& rhs)
{
return Speed(lhs.val / rhs.val);
}
Acceleration operator/(const Speed& lhs, const Time& rhs)
{
return Acceleration(lhs.val / rhs.val);
}
//Define literals
constexpr Distance operator"" _m(long double ld)
{
return Distance(static_cast<double>(ld));
}
constexpr Mass operator"" _kg(long double ld)
{
return Mass(static_cast<double>(ld));
}
constexpr Time operator"" _s(long double ld)
{
return Time(static_cast<double>(ld));
}
constexpr Acceleration operator"" _s2(long double ld)
{
return Acceleration(static_cast<double>(ld));
}
int main()
{
Speed sp = Distance(100)/Time(9.58); //Not bad, but units could be more convenient...
Distance d1 = 100.0_m; //A good distance to run a race
Speed sp1 = 100.0_m/9.58_s; //A human can run this fast
// Speed sp2 = 100.0_m/9.8_s2; //Error: speed is m/s, not m/s^2
// Speed sp3 = 100.0/9.8_s; //Error: 100 has no unit
Acceleration ac1 = sp1/0.5_s; //Faster than any human
return EXIT_SUCCESS;
}
Run Code Online (Sandbox Code Playgroud)
| 归档时间: |
|
| 查看次数: |
190 次 |
| 最近记录: |