【问题标题】:std::make_pair type deductionstd::make_pair 类型推演
【发布时间】:2015-05-01 11:09:49
【问题描述】:

我遇到了一些奇怪的事情,我想解释一下。以下代码 sn -p 提供了一个简单的类模板 type 和两个 operator<<s:一个用于 type 的特化,一个用于 std::pairtype 特化。

#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&lt;&lt; 的签名不匹配:std::pair&lt;T const, T const&gt;。然而,构造一个std::pair 特化(main 中的第二个std::cout 行)以及从operator&lt;&lt; 中删除Tconst 规范对于std::pair,即std::pair&lt;T, T&gt;

编译器消息::

  • gcc 4.9.2

    std_make_pair.cpp: In function 'int main()':
    std_make_pair.cpp:52:35: error: cannot bind 'std::ostream {aka std::basic_ostream<char>}' lvalue to 'std::basic_ostream<char>&&'
       std::cout << std::make_pair(a, b) << std::endl;
                                   ^
    In file included from std_make_pair.cpp:3:0:
    /usr/include/c++/4.9.2/ostream:602:5: note: initializing argument 1 of 'std::basic_ostream<_CharT, _Traits>& std::operator<<(std::basic_ostream<_CharT, _Traits>&&, const _Tp&) [with _CharT = char; _Traits = std::char_traits<char>; _Tp = std::pair<type<float>, type<float> >]'
     operator<<(basic_ostream<_CharT, _Traits>&& __os, const _Tp& __x)
     ^
    
  • clang 3.5(从系统头文件中删除了不可行的函数)

    std_make_pair.cpp:52:13: error: invalid operands to binary expression ('ostream' (aka 'basic_ostream<char>')
      and 'pair<typename __decay_and_strip<const type<float> &>::__type, typename __decay_and_strip<const
      type<float> &>::__type>')
      std::cout << std::make_pair(a, b) << std::endl;
      ~~~~~~~~~ ^  ~~~~~~~~~~~~~~~~~~~~
    
    std_make_pair.cpp:30:1: note: candidate template ignored: can't deduce a type for 'T' which would make
      'const T' equal 'type<float>'
    operator<<(std::basic_ostream<CTy,CTr>& os, std::pair<T const, T const> const& a)
    

所以,问题来了:我是否应该指定一个operator&lt;&lt;Tstd::pair 而不是T const?这不是淡化了我与该功能的任何用户建立的合同,即与T const 我基本上承诺仅以非变异方式使用T

【问题讨论】:

  • 我认为 std::pair 和 std::make_pair 不好(尤其是 std::map,其中 std::make_pair(key, value) 不提供 map::value_type)。
  • @marco-a 感谢您编辑编译器消息。文档不是很清楚如何做到这一点。你使用了&lt;!-- language: ... --&gt; 标签吗?
  • @regnirpsj 不,当项目符号列表需要两倍的代码空间时。应该在某处说明。

标签: c++ templates c++11 stl


【解决方案1】:

第一个失败是因为 std::make_pair 似乎从变量中去除了 const 说明符,而这又与第二个 operator&lt;&lt;: std::pair&lt;T const, T const&gt; 的签名不匹配

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

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

返回:pair&lt;V1, V2&gt;(std::forward&lt;T1&gt;(x), std::forward&lt;T2&gt;(y)); 其中V1V2 确定如下:对于每个Ti,让Uidecay_t&lt;Ti&gt;。那么每个ViX&amp; 如果Ui 等于reference_wrapper&lt;X&gt;,否则ViUi

编译器拒绝您的代码是完全正确的 - 您为 pair&lt;const T, const T&gt; 添加了流操作符,但正在尝试流化 pair&lt;T, T&gt;。解决方案是删除流运算符中额外的 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,无论如何您都不能修改它的内容。

【讨论】:

  • 是的。图书馆试图阻止你陷入const 的混乱;制作一对const,而不是它的元素。
  • std::pair 有两个成员,constness 取决于模板参数,而不是std::pair 本身的运行时constness。还是我错了?
  • @regnirpsj 考虑到即使int 是可变的,您也不能修改int const&amp;
  • @Barry mmh, int const&amp; 实际上是说reference to constant int,它明确禁止变异int。 otoh,int* constconstant pointer to int,所以int 是可变的,只是指向它的指针不能更改。但是,我同意您的观点,并且可能必须向语言律师提交缺陷报告;)
  • @regnirpsj 嗯? 什么的缺陷报告?
猜你喜欢
  • 2013-07-28
  • 1970-01-01
  • 2019-04-15
  • 1970-01-01
  • 2015-12-03
  • 1970-01-01
  • 2015-08-02
  • 1970-01-01
  • 2016-06-13
相关资源
最近更新 更多