首页 > 解决方案 > C++20 格式化程序模板重定义错误

问题描述

我正在尝试做的事情:定义两个fmt::formatter模板,一个用于派生自的类型,std::exception一个用于派生自的类型,std::array<char, N>以便我可以将这些类型作为参数传递给使用fmt::format().

问题:当我只定义一个格式化程序模板时,一切都按预期工作,但是当我定义两者时,我收到一个错误,指出我正在重新定义一个类型:

error: redefinition of ‘struct fmt::v7::formatter<T, char, void>’

代码示例:

template<typename T>
concept Exception = std::is_base_of_v<std::exception, T>;

template<std::size_t arrayLen>
template<typename T>
concept CharArray = std::is_base_of_v<std::array<char, arrayLen>, T>;

template <Exception T>
struct fmt::formatter<T> {

    constexpr auto parse(format_parse_context& ctx) {
        return ctx.begin();
    }

    template <typename FormatContext>
    auto format(const T& ex, FormatContext& ctx) {
        return format_to(ctx.out(), "{}", ex.what());
    }
};

template <CharArray T>
struct fmt::formatter<T> {

    constexpr auto parse(format_parse_context& ctx) {
        return ctx.begin();
    }

    template <typename FormatContext>
    auto format(const T& arr, FormatContext& ctx) {
        const std::string str{arr.data(), strnlen(arr.data(), arr.size())};
        return format_to(ctx.out(), "{}", str);
    }
};

开发环境: g++ 11.1.0,CentOS,fmt来自<spdlog/fmt/bundled/format.h>

我尝试过的:我尝试定义 Exception 和 CharArray 这两个概念,使它们相互排斥。我尝试使用 CharArray 以外的概念,它不是在 size 参数上模板化的。我测试了具有两个void foo(T)功能,一个是模板化的Exception,一个是CharArray按预期工作的。

我在寻找什么:在这一点上,我对解释我做错了什么比对潜在的解决方法更感兴趣。如果涉及到这一点,我有几个解决方法,但我真的想弄清楚我的误解在哪里,这样我就可以从中吸取教训。

提前感谢您的帮助,请在您的回复中保持友好。

解决方案更新:我错误地定义了这个CharArray概念,它没有被 GCC 捕获。fmt由于 GCC 错误,我还需要将模板移动到命名空间内。

标签: c++c++20

解决方案


这个:

template<std::size_t arrayLen>
template<typename T>
concept CharArray = std::is_base_of_v<std::array<char, arrayLen>, T>;

不是有效的声明。我很惊讶编译器没有将其标记为明显格式错误(报告为102289)。

你只能得到一个模板头concept(你可以编写多个这样template的声明的唯一地方是当你在类主体之外定义类模板的成员函数模板时,或者其他类似的东西)。

你可以用 C++20 编写这个概念的方式是:

template <std::size_t N>
void f(std::array<char, N> const&);

template <typename T>
concept CharArray = requires (T t) { f(t); }

基本上,如果你可以f(t)用 a调用T,那么这意味着t要么是某种,std::array<char, N>要么继承自其中。借助 C++20 中的额外 lambda 特性,我们甚至可以将其放入概念本身:

template <typename T>
concept CharArray = requires (T t) {
    []<std::size_t N>(std::array<char, N> const&){}(t);
};

这里的 lambda 只是为了执行与我们对自由函数模板所做的相同的“可调用”检查。


推荐阅读