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

时间:2013-06-05 21:43:03

标签: c++ templates c++11 unique-ptr

我正在试图弄清楚unique_ptr类型在C ++ 11中使用模板的确切方式,并且没有太多运气:具体来说,我正在尝试创建一个插入{的模板函数{1}}如果地图中的键没有值,则给定地图中给定唯一键的值,并将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;

}

非模板功能

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个对象传递给模板函数)?

2 个答案:

答案 0 :(得分:1)

首先,这个:

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, "!");

你会看到断言没有触发(live example)。

您获得编译器错误的原因很可能是您没有在函数模板中使用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中不推荐使用动态异常规范。

答案 1 :(得分:1)

首先,您需要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));
//                    ^^^^^^^^^^^^^