我尝试使用 boost::json
s tag_invoke 在 json 之间存储/加载 std::chrono::minute
s机制。虽然这对于我的自定义小 struct
效果很好,但我无法为 chrono
类型制定正确的语法。
我尝试了两个简单的版本:
void tag_invoke(boost::json::value_from_tag const&, boost::json::value &value, std::chrono::minutes const &minu);
std::chrono::minutes tag_invoke(boost::json::value_to_tag<std::chrono::minutes> const&, boost::json::value const &value);
和
namespace std::chrono {
void tag_invoke(boost::json::value_from_tag const&, boost::json::value &value, /*std::chrono::*/minutes const &minu);
/*std::chrono::*/minutes tag_invoke(boost::json::value_to_tag</*std::chrono::*/minutes> const&, boost::json::value const &value);
}
两个版本都会导致相同的编译器错误 (g++ 11.3),其中包括
/.../_deps/boost-src/libs/json/include/boost/json/value_from.hpp:87: error: no matching function for call to ‘value_from_impl(std::chrono::duration<long int, std::ratio<60> >, std::remove_reference<boost::json::storage_ptr&>::type)’
这似乎是未发现/考虑我的重载的典型标记。
我想念这里的怪癖是什么?
最佳答案
您正确地推测需要将声明放入通过 ADL 关联的命名空间中。
boost::json
和 std::chrono
都适合我:
<强> Live On Coliru
#include <boost/json/src.hpp> //for header-only
#include <chrono>
#include <iostream>
namespace json = boost::json;
using namespace std::chrono_literals;
using M = std::chrono::minutes;
namespace NS {
void tag_invoke(json::value_from_tag, json::value& v, M const& d) {
v = {{"minutes", d.count()}};
}
M tag_invoke(json::value_to_tag<M>, json::value const& v) {
return M(v.at("minutes").as_int64());
}
} // namespace NS
int main() {
auto jv = json::value_from(5min);
std::cout << jv << " " << std::boolalpha
<< (value_to<M>(jv) == 300s) << "\n";
}
输出:
g++ -std=c++20 -O2 -Wall -pedantic -pthread main.cpp -o bj -DNS=boost::json
g++ -std=c++20 -O2 -Wall -pedantic -pthread main.cpp -o sc -DNS=std::chrono
./bj
{"minutes":5} true
./sc
{"minutes":5} true
也许您的标准库实现 std::chrono::minutes
是其他内容的 typedef(未在该确切的命名空间中声明)?我不确定标准是否真的允许这样做
概括!
无论您最终做什么,我建议不要特殊的特定比例。相反,一般支持所有持续时间!
<强> Live On Coliru
#include <boost/json/src.hpp> // for header-only
#include <chrono>
#include <iostream>
namespace json = boost::json;
using namespace std::chrono_literals;
namespace boost::json {
template <typename Rep, typename Ratio>
void tag_invoke(value_from_tag, value& v, std::chrono::duration<Rep, Ratio> const& d) {
v = {{"seconds", static_cast<double>(d / 1.0s)}};
}
template <typename Duration, typename = typename Duration::rep>
Duration tag_invoke(value_to_tag<Duration>, value const& v) {
return std::chrono::duration_cast<Duration>(v.at("seconds").as_double() * 1s);
}
} // namespace boost::json
template <typename D> void foo(D d) {
auto jv = json::value_from(d);
auto roundtrip = value_to<D>(jv);
auto delta = (roundtrip - d) / 1.0ns;
auto ok = std::abs(delta) < 0.000'1; // < 100 femtosecond
std::cout << jv << "\t" << ok << '\t' << delta << "ns\n";
}
int main() {
std::cout << std::boolalpha;
foo(5min);
foo(5.25min);
foo(30h - 15min + 5s);
foo(20ms);
}
打印例如
{"seconds":3E2} true 0ns
{"seconds":3.15E2} true 0ns
{"seconds":1.07105E5} true 0ns
{"seconds":2E-2} true 0ns
或者with -ffast-math
:
{"seconds":3E2} true 0ns
{"seconds":3.15E2} true 2.60209e-08ns
{"seconds":1.07105E5} true 0ns
{"seconds":2E-2} true 0ns
没有 float ?
要减少 FP 表示不精确的问题,请选择一个分辨率:http://coliru.stacked-crooked.com/a/c5b8e084b5d47f3f
更严格地说,您可以在重载中禁止浮点表示: http://coliru.stacked-crooked.com/a/caca13072524b0f9
关于c++ - 如何将 std::chrono::minutes 与 boost::json tag_invoke value_from 配合?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/75503884/