标准::make_pair类型扣除

std::make_pair type deduction

本文关键字:类型 make 标准 pair      更新时间:2023-10-16

我遇到了一些奇怪的事情,我想解释一下。以下代码片段提供了一个简单的类模板type和两个operator<<:一个用于type的专用化,另一个用于type专用化的std::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)以及从std::pairoperator<<中删除Tconst规范是有效的,即std::pair<T, T>.

编译器消息:

  • 海湾合作委员会 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<<采取Tstd::pair而不是T const?这不是淡化我与任何功能用户建立的合同,即我基本上承诺只以非变异方式使用TT const吗?

第一个失败std::make_pair因为它似乎从变量中剥离了 const 说明符,这反过来又与第二个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);

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

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

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;
}

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