std::make_pair 类型推导

std::make_pair type deduction

我遇到了一些奇怪的事情,我想得到解释。以下代码片段提供了一个简单的 class 模板 type 和两个 operator<<:一个用于 type 的特化,一个用于 typestd::pair ] 专业。

#include <ostream>
#include <utility>

template <typename T>
class type {

public:

  T value_;

};

template <typename CTy, typename CTr, typename T>
std::basic_ostream<CTy,CTr>&
operator<<(std::basic_ostream<CTy,CTr>& os, type<T> const& a)
{
  return os << a.value_;
}

template <typename CTy, typename CTr, typename T>
std::basic_ostream<CTy,CTr>&
operator<<(std::basic_ostream<CTy,CTr>& os, std::pair<T const, T const> const& a)
{
  return os << a.first << ',' << a.second;
}

#include <iostream>

int
main()
{
  using float_type = type<float>;

  float_type const a = { 3.14159 };
  float_type const b = { 2.71828 };

#if 0
  std::cout << std::make_pair(a, b)
            << std::endl;
#else
  std::cout << std::pair<float_type const, float_type const>(a, b)
            << std::endl;
#endif
}

main函数提供了一个专业化和该专业化的两个变量。将变量显示为 std::pair 有两种变体。第一个失败是因为 std::make_pair 似乎从变量中删除了 const 说明符,这又与第二个 operator<< 的签名不匹配:std::pair<T const, T const>。但是,构建 std::pair 专业化(main 中的第二 std::cout 行)与从 operator<< 中删除 Tconst 规范一样有效std::pair,即 std::pair<T, T>.

编译器消息::

所以,问题来了:我是否应该指定 operator<<Tstd::pair 而不是 T const?这不是削弱了我与该功能的任何用户建立的合同,即 T const 我基本上承诺仅以 non-mutating 方式使用 T 吗?

The first fails because std::make_pair seems to strip the const specifier from the variables, which in turn doesn't match with the signature of the second operator<<: std::pair<T const, T const>

没错。 make_pair 是一个函数模板,它依赖于 std::decay 显式删除 constvolatile& 限定符:

template <class T1, class T2>
  constexpr pair<V1, V2> make_pair(T1&& x, T2&& y);

Returns: pair<V1, V2>(std::forward<T1>(x), std::forward<T2>(y)); where V1 and V2 are determined as follows: Let Ui be decay_t<Ti> for each Ti. Then each Vi is X& if Ui equals reference_wrapper<X>, otherwise Vi is Ui.

编译器拒绝您的代码是完全正确的 - 您为 pair<const T, const T> 添加了流运算符,但正在尝试流式传输 pair<T, T>。解决方案是只删除流运算符中额外的 const 要求。该函数中没有任何内容要求 pairconst 类型组成——只是类型本身是可流式的,这与它们的 constness 无关。这个没有错:

template <typename CTy, typename CTr, typename T>
std::basic_ostream<CTy,CTr>&
operator<<(std::basic_ostream<CTy,CTr>& os, std::pair<T, T> const& a)
{
  return os << a.first << ',' << a.second;
}

已经通过常量引用获取pair,无论如何您都无法修改其内容。