printf 函数和 fmt 函数之间的重载

如何解决printf 函数和 fmt 函数之间的重载

我有一个类在其构造函数中采用 C printf 的可变参数集,如下所示:

class Foo {
public:
    Foo(const char* str,...) __attribute__((format(printf,2,3)));

现在我希望能够在这个类中使用 fmt library。如果我愿意改变所有呼叫者,我可以像这样切换它:

class Foo {
public:
    template<typename Str,typename... Args>
    Foo(const Str& str,const Args&... args)
        : Foo(str,fmt::make_args_checked<Args...>(str,args...))
    {}

private:
    Foo(fmt::string_view fmt,fmt::format_args args);

但是这个类被用在一百多个地方,“改变世界”是不可行的。所以我想保留两个构造函数,但显然现在我需要一种方法来在它们之间进行选择。我对必须添加新的虚拟参数或其他东西并不感到兴奋。

然后我想,好吧,我也很想强制使用 FMT_STRING() 宏,因为我的 printf 样式代码利用了 GCC 和 clang 中的 printf 格式检查。所以也许我可以用它做一些事情:我可以创建自己的宏,比如 MYFMT(),它会以某种方式调用 FMT_STRING(),或者至少做同样的检查,然后解析为我自己的可以使用的类型选择不同的构造函数;类似:

#define MYFMT(_f) ...
class Foo {
public:
    Foo(const char* str,...);
    Foo(const MyType& str,...) ...

所以,用法类似于:

    auto x = Foo("this is a %s string","printf");
    auto y = Foo(MYFMT("this is a {} string"),"fmt");

但是我已经玩了几个小时并试图围绕 FMT_STRING 宏的工作原理以及我需要做什么来解决我的问题,但我想不出任何东西。也许出于某种原因这是不可能的,但如果有人有任何提示,那就太好了。

FWIW 我的基本编译器是 GCC 10、clang 9 和 MSVC 2019,所以我至少可以依赖 C++17。

解决方法

您可以按以下方式操作 (godbolt):

#include <fmt/core.h>

struct format_string {
  fmt::string_view str;

  constexpr operator fmt::string_view() const { return str; }
};

#define MYFMT(s) format_string{s}

class Foo {
 public:
  template <typename... T>
  Foo(const char* str,T&&... args) {
    fmt::print("printf\n");
  }

  template <typename... T>
  Foo(fmt::format_string<T...> str,T&&... args) {
    fmt::print("fmt\n");
  }
};

int main() {
  Foo("%d\n",42);        // calls the printf overload
  Foo(MYFMT("{}\n"),42); // calls the fmt overload
}

在 C++20 中,这将为您提供 {fmt} 中的编译时检查。请注意,可变参数在 printf 重载中被替换为可变参数模板以避免歧义,因此您将无法应用格式属性。通过稍微调整此解决方案,可能会保留可变参数。

更好的选择是完全避免重载和宏,而是使用不同的函数:

class Foo {
 private:
  Foo() {}
  
 public:
  Foo(const char* str,...) {
    fmt::print("printf\n");
  }

  template <typename... T>
  static Foo format(fmt::format_string<T...> str,T&&... args) {
    fmt::print("fmt\n");
    return Foo();
  }
};

版权声明:本文内容由互联网用户自发贡献,该文观点与技术仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请发送邮件至 dio@foxmail.com 举报,一经查实,本站将立刻删除。

相关推荐


Selenium Web驱动程序和Java。元素在(x,y)点处不可单击。其他元素将获得点击?
Python-如何使用点“。” 访问字典成员?
Java 字符串是不可变的。到底是什么意思?
Java中的“ final”关键字如何工作?(我仍然可以修改对象。)
“loop:”在Java代码中。这是什么,为什么要编译?
java.lang.ClassNotFoundException:sun.jdbc.odbc.JdbcOdbcDriver发生异常。为什么?
这是用Java进行XML解析的最佳库。
Java的PriorityQueue的内置迭代器不会以任何特定顺序遍历数据结构。为什么?
如何在Java中聆听按键时移动图像。
Java“Program to an interface”。这是什么意思?
Java在半透明框架/面板/组件上重新绘画。
Java“ Class.forName()”和“ Class.forName()。newInstance()”之间有什么区别?
在此环境中不提供编译器。也许是在JRE而不是JDK上运行?
Java用相同的方法在一个类中实现两个接口。哪种接口方法被覆盖?
Java 什么是Runtime.getRuntime()。totalMemory()和freeMemory()?
java.library.path中的java.lang.UnsatisfiedLinkError否*****。dll
JavaFX“位置是必需的。” 即使在同一包装中
Java 导入两个具有相同名称的类。怎么处理?
Java 是否应该在HttpServletResponse.getOutputStream()/。getWriter()上调用.close()?
Java RegEx元字符(。)和普通点?