macOS clang++下boost::json tag_invoke转换time_point编译错误求助
问题描述
环境:macOS clang++ 15.0.0
尝试用tag_invoke()实现boost::json::value与std::chrono::time_point之间的转换,代码如下:
#include <chrono> #include <iostream> #include <sstream> #include <string> #include <boost/json.hpp> #include "date.h" // Howard Hinnant's date library, until <chrono> supports parse(). using Time = std::chrono::time_point<std::chrono::system_clock, std::chrono::nanoseconds>; Time tag_invoke(boost::json::value_to_tag<Time>&, const boost::json::value& jv) { Time t; std::istringstream ss{value_to<std::string>(jv)}; ss >> date::parse("%FT%T%Z", t); return t; } int main() { boost::json::value jv = boost::json::parse(R"({"time": "1970-01-01T00:00:00.000000001Z"})"; Time t = value_to<Time>(jv); std::cout << t.time_since_epoch().count() << '\n'; return 0; }
编译时报错No suitable tag_invoke overload found for the type,完整错误信息:
/usr/local/include/boost/json/detail/value_to.hpp:845:5: error: static assertion failed due to requirement '!std::is_same<std::chrono::time_point<std::chrono::system_clock, std::chrono::duration<long long, std::ratio<1, 1000000000>>>, std::chrono::time_point<std::chrono::system_clock, std::chrono::duration<long long, std::ratio<1, 1000000000>>>>::value': No suitable tag_invoke overload found for the type static_assert( ^ /usr/local/include/boost/json/value_to.hpp:96:20: note: in instantiation of function template specialization 'boost::json::detail::value_to_impl<std::chrono::time_point<std::chrono::system_clock, std::chrono::duration<long long, std::ratio<1, 1000000000>>>, boost::json::detail::no_context>' requested here return detail::value_to_impl( cat(), value_to_tag<bare_T>(), jv, ctx ); ^ /usr/local/include/boost/json/value_to.hpp:148:12: note: in instantiation of function template specialization 'boost::json::value_to<std::chrono::time_point<std::chrono::system_clock, std::chrono::duration<long long, std::ratio<1, 1000000000>>>, boost::json::detail::no_context>' requested here return value_to<T>( jv, detail::no_context() ); ^ src/tag_invoke.cpp:29:14: note: in instantiation of function template specialization 'boost::json::value_to<std::chrono::time_point<std::chrono::system_clock, std::chrono::duration<long long, std::ratio<1, 1000000000>>>>' requested here Time t = value_to<Time>(jv);
封装为普通函数Time parse_time(...)可正常运行,但使用tag_invoke()则报错。
问题分析与解决
1. 语法错误修正
main函数中boost::json::parse的字符串末尾缺少右括号,导致基础语法错误,修正后:
boost::json::value jv = boost::json::parse(R"({"time": "1970-01-01T00:00:00.000000001Z"})");
2. ADL查找失败问题
Boost.JSON的value_to依赖**参数依赖查找(ADL)**定位tag_invoke重载。你的Time是全局命名空间下的typedef,tag_invoke也定义在全局命名空间,无法被ADL正确识别。有两种解决方式:
- 方式一:将
tag_invoke放入boost::json命名空间
扩展Boost.JSON命名空间,将重载放入其中,确保内部逻辑能找到:namespace boost::json { Time tag_invoke(value_to_tag<Time>&, const value& jv) { Time t; std::istringstream ss{value_to<std::string>(jv)}; ss >> date::parse("%FT%T%Z", t); return t; } } // namespace boost::json - 方式二:将类型与
tag_invoke放入自定义命名空间
把Time和对应的tag_invoke重载放在同一个自定义命名空间,利用ADL规则让编译器找到:
后续main函数中使用namespace my_time { using Time = std::chrono::time_point<std::chrono::system_clock, std::chrono::nanoseconds>; Time tag_invoke(boost::json::value_to_tag<Time>&, const boost::json::value& jv) { Time t; std::istringstream ss{boost::json::value_to<std::string>(jv)}; ss >> date::parse("%FT%T%Z", t); return t; } } // namespace my_timemy_time::Time即可。
3. JSON对象访问错误
当前代码直接将整个JSON对象({"time": "..."})传给value_to<Time>,但你的tag_invoke期望处理JSON字符串值,需提取对应字段:
Time t = value_to<Time>(jv.at("time"));
修正后的完整代码
#include <chrono> #include <iostream> #include <sstream> #include <string> #include <boost/json.hpp> #include "date.h" // Howard Hinnant's date library, until <chrono> supports parse(). using Time = std::chrono::time_point<std::chrono::system_clock, std::chrono::nanoseconds>; namespace boost::json { Time tag_invoke(value_to_tag<Time>&, const value& jv) { Time t; std::istringstream ss{value_to<std::string>(jv)}; ss >> date::parse("%FT%T%Z", t); return t; } } // namespace boost::json int main() { boost::json::value jv = boost::json::parse(R"({"time": "1970-01-01T00:00:00.000000001Z"})"); Time t = boost::json::value_to<Time>(jv.at("time")); std::cout << t.time_since_epoch().count() << '\n'; return 0; }
内容的提问来源于stack exchange,提问作者John Duffy
相关产品推荐
相关产品推荐

