实现模板运算符<<用于 std::p air<const char*、std::optional<T>> 处理常量值

Implementing template operator<< for std::pair<const char*, std::optional<T>> with Handling of Constant Values

提问人:Fanteria 提问时间:9/20/2023 更新时间:9/26/2023 访问量:62

问:

我正在尝试编写一个实现 .此运算符已为按值传递或按常量引用传递的类型实现,如以下示例所示:operator<<std::pair<const char*, std::optional<T>>

MyStream& operator<<(MyStream&, std::pair<const char*, int>);
MyStream& operator<<(MyStream&, std::pair<const char*, const MyClass&>);

现在,我面临的挑战是确定是将运算符用于值还是常量引用。我探索了两种方法来解决这个问题。第一种方法涉及单独处理不同的类型,如下所示:if constexpr

if constexpr (std::is_same<T, int>::value || std::is_same<T, bool>::value) {
  os << std::pair<const char*, T>{t.first, *t.second};
} else {
  os << std::pair<const char*, const T&>{t.first, *t.second};
}

第二种方法涉及优先实现重载函数,以确定要使用的适当运算符:

template <std::size_t N>
struct overloadPriority : overloadPriority<N - 1> {};

template <>
struct overloadPriority<0> {};

template <typename T>
void serialize(overloadPriority<1>, MyStream& os, const char* key, const T& value) {
  os << std::pair<const char*, const T&>{key, value};
}

template <typename T>
void serialize(overloadPriority<0>, MyStream& os, const char* key, const T& value) {
  os << std::pair<const char*, T>{key, value};
}

我的问题是双重的:首先,有没有办法处理常量值,例如(没有引用),它可以解释为常量引用或值?其次,出于好奇,有没有其他方法可以实现此功能?std::pair<const char*, const int>

C++ 模板 C++17

评论

1赞 Jarod42 9/20/2023
仅使用 const ref 进行序列化 Demo。将有一个隐式复制/转换从 到 。pair<const char*, const int&>pair<const char*, int>
0赞 Fanteria 9/20/2023
谢谢你,你是对的。我在稍微错误的地方寻找问题。真正的问题在于另一个更适合该类型的模板。我会在晚上写下我的答案。

答:

0赞 Fanteria 9/26/2023 #1

在最初的问题中,我错误地询问了问题的错误方面。我试图解决隐式转换的问题,但实际问题在于另一个模板,该模板处理基本类型的重载实现。

// MyStream& operator<<(MyStream&, const MyClass&) must be implemented
MyStream& operator<<(MyStream& os, std::pair<const char*, const MyClass&> value) {
    MyStream block;
    block << value.second;
    os << std::pair<const char*, const MyStream&>{value.first, block};
}

此函数允许将数据序列化为新块,前提是我可以将数据序列化到打开的块中。问题源于以下事实:返回 ,例如,返回 。此类型由上面提到的模板重载,而不是由实现的 .std::optional<T>::value()const T&std::optional<int>const int&MyStream& operator<<(MyStream&, std::pair<const char*, int>)

要解决这个问题,必须检查函数是否存在。在 C++20 中,这可以使用 require 来实现。但是,由于我使用的是 C++17,因此我需要求助于 SFINAE。我在这个相关问题中找到了一些关于这个问题的有用信息。

评论

0赞 speed_of_light 9/29/2023
因此,尊重您的可选性是问题所在。为什么不让模板参数成为可选参数呢?然后,您可以在没有 sfinae 的情况下在运算符内部进行序列化