我正在寻找std::chrono
期间的强类型解决方案。我的持续时间类型取决于仅运行时值。我使用类似于工厂的类使用运行时值在持续时间之间进行转换。例如:
#include <chrono>
#include <cstdio>
using dseconds = std::chrono::duration<double>;
using blee = std::chrono::duration<double, std::ratio<1,1>>;
using tick = std::chrono::duration<size_t, std::ratio<1,64>>;
struct converter {
tick to_tick(dseconds s) const {
return std::chrono::duration_cast<tick>(s / runtime_ratio);
}
tick to_tick(blee b) const {
return std::chrono::duration_cast<tick>(b);
}
private:
double runtime_ratio = 0.5;
};
int main(int, char**) {
converter c;
printf("%zu", c.to_tick(dseconds{1}).count());
printf("%zu", c.to_tick(blee{1}).count());
}
该示例在compiler explorer上可用。
请注意,以秒为单位的转换会应用该比率,这与blee的转换不同。由于dseconds
和blee
实际上是同一类型,因此无法编译。
<source>:13:10: error: 'tick converter::to_tick(blee) const' cannot be overloaded with 'tick converter::to_tick(dseconds) const'
tick to_tick(blee b) const {
^~~~~~~
<source>:9:10: note: previous declaration 'tick converter::to_tick(dseconds) const'
tick to_tick(dseconds s) const {
^~~~~~~
我尝试使用模板化别名来区分blee,但这没有用。我试过在其他名称空间或结构中嵌套别名,但也没有用。我读过fluentc++的类似帖子,但我不理解,而且api确实很丑陋且具有侵入性。
有没有办法用相同的类型和比率强类型2持续时间别名?
答案 0 :(得分:4)
我会再次建议:使用继承。
现在,您的问题是通过using
使用类型别名。这不会创建新类型,只会创建旧类型的新名称。您正在尝试使用相同的类型重载两次,这是没有意义的,也是不可能的,因为重载并不关心新名称。
但是继承创建类型。那是它的工作;这就是它的目的。
借助此方法,您可以轻松地创建有时称为“强typedef”的东西-一种新颖,独特的类型,否则其行为几乎与您所获取的东西完全一样。
它确实需要少量的体操运动,但最终结果却很性感,并且可以再花半个小时的时间对其进行微不足道的改善。 (例如,向上转换的ctor中的一点移动语义可能不会受到伤害……)。
我们在这里:
#include <chrono>
#include <cstdio>
using dseconds = std::chrono::duration<double>;
struct blee : std::chrono::duration<double, std::ratio<1,1>>
{
using DurationType = std::chrono::duration<double, std::ratio<1,1>>;
using DurationType::DurationType;
blee(const DurationType& other) : DurationType(other) {}
};
struct tick : std::chrono::duration<size_t, std::ratio<1,64>>
{
using DurationType = std::chrono::duration<size_t, std::ratio<1,64>>;
using DurationType::DurationType;
tick(const DurationType& other) : DurationType(other) {}
};
struct converter {
tick to_tick(dseconds s) const {
return std::chrono::duration_cast<tick::DurationType>(s / runtime_ratio);
}
tick to_tick(blee b) const {
return std::chrono::duration_cast<tick::DurationType>(b);
}
private:
double runtime_ratio = 0.5;
};
int main(int, char**) {
converter c;
printf("%zu", c.to_tick(dseconds{1}).count());
printf("%zu", c.to_tick(blee{1}).count());
}
所以,好的,您必须花几行时间来设置类型。而且,好的,您必须稍微扩展duration_cast
通话。
但是说实话,要获得不依赖于黑客的解决方案似乎要付出很小的代价!
(实际上,您实际上只需要将其应用于blee
,但出于对称起见,我都将其应用了。这比将tick
保留为简单类型更好还是更坏别名取决于读者。)
实际上,我什至可以说这是唯一在语义上“正确”的解决方案,因为您实际上是在创建语义上新的类型,而这并不是别名。别名是为现有类型创建一个方便的替代名称。
答案 1 :(得分:2)
好的,我发现了某种黑客手段。如果您使用std::ratio<2,2>
(无论如何都等同于std::ratio<1,1>
),则编译器将停止抱怨并将dseconds
和blee
视为不同类型。
如果有人有更好的解决方案,我将继续公开这个问题。
#include <chrono>
#include <cstdio>
using dseconds = std::chrono::duration<double>;
using blee = std::chrono::duration<double, std::ratio<2,2>>;
using tick = std::chrono::duration<size_t, std::ratio<1,64>>;
struct converter {
tick to_tick(dseconds s) const {
return std::chrono::duration_cast<tick>(s / runtime_ratio);
}
tick to_tick(blee b) const {
return std::chrono::duration_cast<tick>(b);
}
private:
double runtime_ratio = 0.5;
};
int main(int, char**) {
converter c;
printf("%zu", c.to_tick(dseconds{1}).count());
printf("%zu", c.to_tick(blee{1}).count());
}