有没有一种方法可以禁用用户定义类的fmt范围格式化程序?

8

我有一个简单的类,它有一个tostring()方法:

class MyClass {
  public:

    std::string tostring() const;

    static iterator begin();
    static iterator end();
};

尽管我现在使用fmt库,但这段代码是从没有使用fmt的代码移植过来的,因此许多旧类实现了tostring()方法,并且我有一个模板,可以为任何具有该方法的类生成fmt::formatter。它一直运行良好。

然而,这个特定的类还有begin/end函数。它们是静态的(这个类类似于枚举,并且可以遍历所有可能的值),不应与格式化有任何关系。

一切都很好,直到我需要为一些不同的代码包含fmt/ranges.h。问题是,有一个范围格式化程序看到了begin/end函数,并希望将该类格式化为一个范围。现在,如果我尝试格式化该类,我会得到格式化程序的二义性实例化(一个是我想要使用的模板,另一个是范围格式化程序)。

有办法让范围格式化程序忽略这个类吗?

完整示例:

#include <type_traits>
#include <utility>
#include <string>
#include <vector>
#include <fmt/format.h>
// #include <fmt/ranges.h>


// Create formatter for any class that has a tostring() method

template <typename T>
struct has_tostring_member {
private:
  template <typename U>
  static std::true_type  test( decltype(&U::tostring) );
  template <typename U>
  static std::false_type test(...);
public:
  using result = decltype(test<T>(0) );
  static constexpr bool  value = result::value;
};

template <typename T, typename Char>
struct  fmt::formatter<T, Char,
                       std::enable_if_t<has_tostring_member<T>::value > >
  : formatter<basic_string_view<Char>, Char> {
  template <typename FormatContext>
  auto
  format( const T& e, FormatContext& ctx )
  {
    return formatter<string_view>::format( e.tostring(), ctx );
  }
};


class MyClass
{
public:
  explicit MyClass(int i) : value(i) {}

  std::string tostring() const { return std::to_string(value); }

  static auto begin() { return std::begin(static_data); }
  static auto end() { return std::end(static_data); }

private:
  int  value;
  static const std::vector<std::string> static_data;
};


 const std::vector<std::string> MyClass::static_data{ "a", "b", "c" };

int main(void) {
  MyClass c{10};

  fmt::print("c is {}\n", c);

  return 0;
}

如果我有一个完整的MyClass类的fmt::formatter专门化版本,那么就没有歧义了。但是如果像例子中一样使用部分专门化,则取消注释 "#include <fmt/ranges.h>" 将导致模板实例化存在歧义。


换句话说,创建 [mcve] - eerorika
1个回答

4
这里是选项(您已经发现了):
  1. 不要包括 fmt/ranges.h
  2. 提供一个完整的 formatter 特化实现。
请注意,如果您已经为具有 tostring 的所有类型实现了通用格式化程序,则可以在一行中完成(2)(https://godbolt.org/z/cW3WzaP6f):
template <> struct fmt::formatter<MyClass> : tostring_formatter<MyClass> {};

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接