首页
学习
活动
专区
圈层
工具
发布
社区首页 >问答首页 >eigen3与libfmt >= 9.0

eigen3与libfmt >= 9.0
EN

Stack Overflow用户
提问于 2022-09-16 18:18:11
回答 3查看 274关注 0票数 5

我曾经能够将Eigen3数组/矩阵传递给spdlog,而spdlog内部使用libfmt。从libfmt 9.0.0开始,这些类型不再由libfmt格式化,而无需进一步的代码。

自定义类型在fmt中是通过对类型进行专门化fmt::formatter<T>来支持的;fmt9文档进一步解释说,从ostream_formatter派生这种专门化将使用现有的operator<<,而特征类可以方便地提供这些operator<<

Eigen 使用CRTP继承和我将专门针对以下所有Eigen::DenseBase<T>类型:

代码语言:javascript
复制
#include<fmt/ostream.h>
#include<eigen3/Eigen/Core>
#include<iostream>

template <typename T> struct fmt::formatter<T,std::enable_if_t<std::is_base_of_v<Eigen::DenseBase<T>,T>>>: ostream_formatter {};

int main(){
    Eigen::Array3f a(1,2,3);
    std::cout<<fmt::format("{}",a)<<std::endl;
}

既然我在发帖,显然这件事进展得不好:

代码语言:javascript
复制
In file included from /usr/include/fmt/format.h:48,
                 from /usr/include/fmt/ostream.h:18,
                 from /tmp/aa.cpp:1:
/usr/include/fmt/core.h: In instantiation of ‘constexpr fmt::v9::detail::value<Context> fmt::v9::detail::make_value(T&&) [with Context = fmt::v9::basic_format_context<fmt::v9::appender, char>; T = Eigen::Array<float, 3, 1>&]’:
/usr/include/fmt/core.h:1771:29:   required from ‘constexpr fmt::v9::detail::value<Context> fmt::v9::detail::make_arg(T&&) [with bool IS_PACKED = true; Context = fmt::v9::basic_format_context<fmt::v9::appender, char>; fmt::v9::detail::type <anonymous> = fmt::v9::detail::type::custom_type; T = Eigen::Array<float, 3, 1>&; typename std::enable_if<IS_PACKED, int>::type <anonymous> = 0]’
/usr/include/fmt/core.h:1895:77:   required from ‘constexpr fmt::v9::format_arg_store<Context, Args>::format_arg_store(T&& ...) [with T = {Eigen::Array<float, 3, 1, 0, 3, 1>&}; Context = fmt::v9::basic_format_context<fmt::v9::appender, char>; Args = {Eigen::Array<float, 3, 1, 0, 3, 1>}]’
/usr/include/fmt/core.h:1912:31:   required from ‘constexpr fmt::v9::format_arg_store<Context, typename std::remove_cv<typename std::remove_reference<Args>::type>::type ...> fmt::v9::make_format_args(Args&& ...) [with Context = fmt::v9::basic_format_context<fmt::v9::appender, char>; Args = {Eigen::Array<float, 3, 1, 0, 3, 1>&}]’
/usr/include/fmt/core.h:3184:44:   required from ‘std::string fmt::v9::format(fmt::v9::format_string<T ...>, T&& ...) [with T = {Eigen::Array<float, 3, 1, 0, 3, 1>&}; std::string = std::__cxx11::basic_string<char>; fmt::v9::format_string<T ...> = fmt::v9::basic_format_string<char, Eigen::Array<float, 3, 1, 0, 3, 1>&>]’
/tmp/aa.cpp:7:24:   required from here
/usr/include/fmt/core.h:1751:7: error: static assertion failed: Cannot format an argument. To make type T formattable provide a formatter<T> specialization: https://fmt.dev/latest/api.html#udt
 1751 |       formattable,
      |       ^~~~~~~~~~~
/usr/include/fmt/core.h:1751:7: note: ‘formattable’ evaluates to false

我能解释一下如何正确地做这件事吗?我想在这里理解c++的含义,并在此基础上给出一个可行的解决方案。谢谢!

EN

回答 3

Stack Overflow用户

回答已采纳

发布于 2022-09-17 14:51:48

问题是,formatter将字符(代码单元)类型作为第二个模板参数,并通过可能无法工作的enable_if_t传递void。修复方法是传递char或其他代码单元类型:

代码语言:javascript
复制
template <typename T>
struct fmt::formatter<
  T,
  std::enable_if_t<
    std::is_base_of_v<Eigen::DenseBase<T>, T>,
    char>> : ostream_formatter {};
//  ^ code unit type

天栓:https://godbolt.org/z/x1Tr3MPYY

票数 4
EN

Stack Overflow用户

发布于 2022-09-17 20:29:01

如果您有c++20,您也可以使用一个概念,以防止进入这个SFINAE / void陷阱:

代码语言:javascript
复制
template <typename T>
    requires std::is_base_of_v<Eigen::DenseBase<T>, T>
struct fmt::formatter<T> : ostream_formatter {};

https://godbolt.org/z/WGG77vGEr

票数 5
EN

Stack Overflow用户

发布于 2022-11-14 22:25:04

Eigen::EigenBase<Derived>的其他解决方案在大多数情况下运行良好,但我发现它们没有涵盖来自Eigen::DenseBase<Derived>::format()的格式化Eigen::WithFormat<ExpressionType>输出。

为此,您需要添加

代码语言:javascript
复制
template <typename T> struct fmt::formatter<Eigen::WithFormat<T>> : ostream_formatter {};

在正确的解决方案不太想工作的情况下,还值得一提的是设置FMT_DEPRECATED_OSTREAM定义的快速而肮脏的选项,该选项恢复了预v9行为。

票数 0
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/73748856

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档