c++ 当给定const string&?[duplicate]时,为什么make_pair〈string,string>()不调用复制构造器?

n7taea2i  于 2023-03-25  发布在  其他
关注(0)|答案(2)|浏览(147)

此问题在此处已有答案

C++11 make_pair with specified template parameters doesn't compile(1个答案)
Weird compiler error: Cannot convert parameter from 'int' to 'int &&'(4个答案)
std::make_pair, c++11 and explicit template parameters [duplicate](2个答案)
15小时前关门了。
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));
vlju58qv

vlju58qv1#

假设是C++11或更高版本:
std::make_pair不应该与显式指定的模板参数一起使用。它们旨在通过转发引用从函数参数推导出来。std::make_pair的签名是

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

这表明T1T2被用作转发引用,因此不应该显式指定。(V1/V2是通过decay从T1/T2计算出来的。)
显式指定模板参数会破坏转发行为。使用string作为模板参数,您会在函数参数中获得string&&,这是一个不接受左值的右值引用。您需要提供const string&作为T的模板参数,以使T&&也成为const string&
但别这样写

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之前编译。尽管如此,指定模板参数也是多余的。

g52tjvyc

g52tjvyc2#

根据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);

相关问题