传递唯一的指针给模板函数

Passing unique pointer to template function

本文关键字:函数 指针 唯一      更新时间:2023-10-16

我想弄清楚unique_ptr类型是如何在c++ 11中与模板一起发挥作用的,并且我没有太多的运气:具体来说,我试图制作一个模板函数,如果在给定的地图中还没有键的值,则在给定的地图中插入一个unique_ptr值,并将unique_ptr指向的值的所有权移动到地图中的值;如果键已经存在,则抛出运行时错误。

现在,移动unique_ptr的值是非常简单的,如果您不需要将其传递给函数:

#include <iostream>
#include <memory>
#include <unordered_map>
using namespace std;
int main(int argc, char *argv[])
{
    unordered_map<char, unique_ptr<int> > testMap;
    char key1 = 'A';
    unique_ptr<int> val1(new int(1));
    testMap[key1] = move(val1);
    // Print the results
    cout << "testMap[" << key1 << "] = " << *testMap[key1] << endl;
    return 0;
}
<标题> Non-template函数

unique_ptr传递给函数有点复杂:

#include <iostream>
#include <memory>
#include <unordered_map>
using namespace std;
void moveValueForUniqueKey(unordered_map<char, unique_ptr<int> >& targetMap, char key, unique_ptr<int> value) throw(char)
{
    // Check if the key is already in the map
    auto it = targetMap.find(key);
    if (it != targetMap.end())
    {
        throw key;
    }
    else
    {
        targetMap[key] = move(value);
    }
}
int main(int argc, char *argv[])
{
    unordered_map<char, unique_ptr<int> > testMap;
    char key1 = 'A';
    unique_ptr<int> val1(new int(1));
    // Try inserting the first key-value pair
    try
    {
        moveValueForUniqueKey(testMap, key1, move(val1));
    }
    catch (char& duplicateKey)
    {
        cerr << "Key '" << duplicateKey << "' already in map." << endl;
    }
    // Print the key-value pairs
    for (pair<const char, unique_ptr<int> >& entry : testMap)
    {
        cout << "testMap['" << entry.first << "'] = " << *entry.second << endl;
    }
    unique_ptr<int> val2(new int(2));
    // Try inserting the key again
    try
    {
        moveValueForUniqueKey(testMap, key1, move(val2));
    }
    catch (char& duplicateKey)
    {
        cerr << "Key '" << duplicateKey << "' already in map." << endl;
    }
    // Print the key-value pairs again
    for (pair<const char, unique_ptr<int> >& entry : testMap)
    {
        cout << "testMap['" << entry.first << "'] = " << *entry.second << endl;
    }
    return 0;
}

这段代码输出:

testMap['A'] = 1
Key 'A' already in map.
testMap['A'] = 1
<标题> 函数模板

现在,当我尝试制作这个函数的模板时,用:

替换之前的moveValueForUniqueKey(...)声明/实现:
template<typename K, typename V, typename M>
void moveValueForUniqueKey(M targetMap, K key, unique_ptr<V> value) throw(char)
{
    // Check if the key is already in the map
    auto it = targetMap.find(key);
    if (it != targetMap.end())
    {
        throw key;
    }
    else
    {
        targetMap[key] = move(value);
    }
}
// Instantiate template function
template
void moveValueForUniqueKey(unordered_map<char, unique_ptr<int> >& targetMap, char key, unique_ptr<int> value) throw(char);

我只是得到编译错误use of deleted function ‘constexpr std::pair<_T1, _T2>::pair(const std::pair<_T1, _T2>&) [with _T1 = const char, _T2 = std::unique_ptr<int>, std::pair<_T1, _T2> = std::pair<const char, std::unique_ptr<int> >]’

这里到底发生了什么,你怎么能完成我在这里尝试(通过unique_ptr对象到模板函数使用移动语义)?

首先,这个:

remove_reference<unique_ptr<int>&>::type

等价于:

unique_ptr<int>

我看不出这里需要remove_reference。要说服自己,试着这样做:

#include <type_traits>
#include <memory>
static_assert(std::is_same<
    remove_reference<unique_ptr<int>&>::type, 
    unique_ptr<int>>::value, "!");

并且您将看到断言没有触发(实例)。

你得到的编译错误最有可能的原因是你没有在你的函数模板中使用typename消歧器:

template<typename K, typename V, typename M>
void moveValueForUniqueKey(M targetMap, K key, 
    typename remove_reference<unique_ptr<V>&>::type value) throw(char)
//  ^^^^^^^^
{
    // ...
}

但是,这里没有理由使用remove_reference:

template<typename K, typename V, typename M>
void moveValueForUniqueKey(M targetMap, K key, unique_ptr<V> value) throw(char)
//                                             ^^^^^^^^^^^^^
{
    // ...
}

最后,请记住动态异常规范在c++ 11中已被弃用。

首先需要typename,因为您要通过模板参数获得类型:

template<typename K, typename V, typename M>
void moveValueForUniqueKey(
    M targetMap, K key, typename remove_reference<unique_ptr<V>&>::type value) throw(char)
    //                  ^^^^^^^^
{...}

但是你不需要签名remove_refrence<T&>::type。你为什么不直接用T呢?

template<typename K, typename V, typename M>
void moveValueForUniqueKey(M targetMap, K key, unique_ptr<V> value) throw(char)
{...}

std::unique_ptr不能被复制,所以您应该简单地将的左值移到参数中。例如,您的主程序中有一个无效行。改变这个:

moveValueForUniqueKey(testMap, key1, move(val2));

moveValueForUniqueKey(move(testMap), key1, move(val2));
//                    ^^^^^^^^^^^^^