代码之家  ›  专栏  ›  技术社区  ›  MWB

当给定const字符串&时,为什么make_pair<string,string>()不调用复制构造函数?

  •  2
  • MWB  · 技术社区  · 2 年前

    GCC和Clang均拒绝编制本报告:

    #include <string>
    #include <utility>
    
    using namespace std;
    
    int main() {
        const string s = "12345";
        const string& r = s;
    
        auto p = std::make_pair<string, string>(r, r);
    }
    

    GCC表示:

    error: cannot bind rvalue reference of type ‘std::__cxx11::basic_string<char>&&’ to lvalue of type ‘const std::string’ {aka ‘const std::__cxx11::basic_string<char>’}
    

    而Clang说:

    error: no matching function for call to 'make_pair'
    

    既然我给了 make_pair 显式类型,为什么它不从 const string& ?


    这个编译:

    auto p = std::make_pair<string, string>(string(r), string(r));
    
    2 回复  |  直到 2 年前
        1
  •  7
  •   user17732522    2 年前

    假设C++11或更高版本:

    std::make_pair 不应与显式指定的模板参数一起使用。它们旨在通过转发引用从函数自变量中推导出来。的签名 std::make_pair

    template<class T1, class T2>
    constexpr std::pair<V1, V2> make_pair(T1&& t, T2&& u);
    

    这表明 T1 T2 用作转发引用,因此不应显式指定。( V1 / V2 是根据计算的 T1 / T2 通过衰变。)

    显式指定模板参数会破坏转发行为。具有 string 作为模板参数 string&& 在函数参数中,它是一个不接受左值的右值引用。您需要提供 const string& 作为的模板参数 T 制作 T&& 而且 常量字符串& .

    但不要那样做,只写

    auto p = std::make_pair(r, r);
    

    正如预期用途一样。


    在C++11之前,没有转发引用 std::make_pair 看起来是这样的:

    template <class T1, class T2>
    std::pair<T1, T2> make_pair(T1 t, T2 u);
    

    因此,您的问题中的代码将在C++11之前编译。尽管如此,指定模板参数在当时也是多余的。

        2
  •  2
  •   AndyG    2 年前

    pairs.spec 的定义 make_pair 看起来是这样的:

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

    并返回:

    pair<unwrap_ref_decay_t<T1>, unwrap_ref_decay_t<T2>>(std::forward<T1>(x), std::forward<T2>(y))
    

    unwrap_ref_decay_t 只是 std::decay_t 在这里,因为您没有使用 reference_wrapper (以及 std::decay<string> 只是 string ). 因此,当您显式命名模板参数时,最终会得到以下签名:

    constexpr pair<string, string> make_pair(string&& x, string&& y);
    

    查看函数参数是如何从“转发引用”中导出的( T&& )到r值参考( string&& )?

    由于您提供 const string& 参数,它们无法转换,因此编译失败。这就是为什么当您显式传递 string(r) 它开始工作。

    解决方案是不传递类型参数,如 user17732522

    auto p = std::make_pair(r, r);