std::pair 结合 const std:unique_ptr 给出 "no matching function call" 错误

std::pair gives "no matching function call" error in combination with const std:unique_ptr

我偶然发现了我不理解的 std::make_pair 行为。给定以下代码

#include <iostream>

using namespace std;

#include <memory>
#include <utility>

class TestClass
{
    public:
        TestClass(const std::string& str) : str{std::make_unique<const std::string>(str)} {};
        ~TestClass() = default; // (1)

    private:
        std::unique_ptr<const std::string> str{};  // (2)
        // const std::unique_ptr<const std::string> str{};  // (3)
};



int main()
{
    // is fine all the time
    TestClass myTestClass = TestClass("myTestClass");  // (4)

    // doesn't work at all  
    std::make_pair("myTestClassKey", myTestClass);  // (5)

    // works, but only wit (1) commented out and (2) instead of (3)
    std::make_pair("myTestClassKey", TestClass("myTestClass"));  // (6)

    return 0;
}

TestClass 中的第 (1) 至 (3) 行让我很头疼。尽管第 (4) 行的工作与第 (1) 和 (2) 或 (3) 行的注释无关,但第 (5) 行根本不起作用,而第 (6) 行仅在第 (1) 行被注释掉且第 (2) 行时编译) 代替第 (3) 行。我收到的编译器错误总是类似于:

||=== Build: Debug in test (compiler: GNU GCC Compiler) ===|
/usr/include/c++/9/bits/stl_pair.h||In instantiation of ‘constexpr std::pair<typename std::__decay_and_strip<_Tp>::__type, typename std::__decay_and_strip<_T2>::__type> std::make_pair(_T1&&, _T2&&) [with _T1 = const char (&)[15]; _T2 = TestClass; typename std::__decay_and_strip<_T2>::__type = TestClass; typename std::__decay_and_strip<_Tp>::__type = const char*]’:|
/home/johndoe/Coding/test/main.cpp|26|required from here|
/usr/include/c++/9/bits/stl_pair.h|529|error: no matching function for call to ‘std::pair<const char*, TestClass>::pair(const char [15], TestClass)’|
/usr/include/c++/9/bits/stl_pair.h|436|note: candidate: ‘template<class ... _Args1, long unsigned int ..._Indexes1, class ... _Args2, long unsigned int ..._Indexes2> std::pair<_T1, _T2>::pair(std::tuple<_Args1 ...>&, std::tuple<_Args2 ...>&, std::_Index_tuple<_Indexes1 ...>, std::_Index_tuple<_Indexes2 ...>)’|
/usr/include/c++/9/bits/stl_pair.h|436|note:   template argument deduction/substitution failed:|
/usr/include/c++/9/bits/stl_pair.h|529|note:   mismatched types ‘std::tuple<_Tps ...>’ and ‘const char [15]’|
/usr/include/c++/9/bits/stl_pair.h|375|note: candidate: ‘template<class ... _Args1, class ... _Args2> std::pair<_T1, _T2>::pair(std::piecewise_construct_t, std::tuple<_Args1 ...>, std::tuple<_Args2 ...>)’|

...

/usr/include/c++/9/bits/stl_pair.h|529|note:   candidate expects 0 arguments, 2 provided|
||=== Build failed: 9 error(s), 2 warning(s) (0 minute(s), 0 second(s)) ===|

简而言之,这是为什么?到目前为止我唯一的想法是它可能与 std::unique_ptr 的移动/复制构造有关?但是为什么第(1)行会引起麻烦呢?

让我们分解一下您的代码的作用:

~TestClass() = default; // (1)

您将析构函数明确定义为默认析构函数。这算作用户声明的析构函数。

std::unique_ptr<const std::string> str{};  // (2)

声明一个非常量 unique_ptr 字段。该字段可以改变,因此从中移出。

// const std::unique_ptr<const std::string> str{};  // (3)

声明一个常量 unique_ptr 字段。对象初始化后,您将不能离开该字段。

TestClass myTestClass = TestClass("myTestClass");  // (4)

通过复制省略直接初始化 myTestClass。这意味着这里没有 copy-/move-constructor 或赋值发生。 (https://en.cppreference.com/w/cpp/language/copy_elision)

std::make_pair("myTestClassKey", myTestClass);  // (5)

创建一个 std::pair,将 myTestClass 的副本作为第二个值。 TestClass 无法复制 - 没有定义隐式复制构造函数,因为 unique_ptr 也没有!

std::make_pair("myTestClassKey", TestClass("myTestClass"));  // (6)

用纯右值(“纯”右值)初始化 std::pair,它是表达式 TestClass("myTestClass") 的结果。这种类型的初始化需要一个可用的移动构造函数。为您自动定义隐式声明的移动构造函数,前提是:

显式默认的析构函数 (1) 被算作用户声明的析构函数,这意味着当 (1) 未注释时不会发出隐式声明的移动构造函数,因此 (6) 出现编译错误。