I'm trying to figure out how exactly the unique_ptr
type plays with templates in C++11, and am not having much luck: Specifically, I'm trying to make a template function which inserts a unique_ptr
value for a given unique key in a given map if there is not already a value for the key in the map, and moves ownership of the value pointed to by the unique_ptr
to the value in the map; If the key is already present, a runtime error is thrown.
Now, moving the value of a unique_ptr
is quite straightforward if you don't have to pass it to a function:
#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 function
Passing the unique_ptr
to a function is a bit more complicated:
#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;
}
This code outputs:
testMap['A'] = 1
Key 'A' already in map.
testMap['A'] = 1
Function template
Now, when I try to make a template of this function, replacing the previous declaration/implementation of moveValueForUniqueKey(...)
with:
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);
I simply get the compiler error 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> >]’
.
What exactly is going on here, and how can you accomplish what I'm trying here (pass unique_ptr
objects into template functions using move semantics)?