hashing function lambda failing to compile with unordered_map - c++

The following code is failing to compile with
error C3497: you cannot construct an instance of a lambda`:
auto hasher = [&](const cv::Vec3b& color) -> size_t {
std::hash<int> int_hasher;
return int_hasher(color[0]) + int_hasher(color[1]) + int_hasher(color[2]);
// the above code is probably a wrong way of constructing a hash,
// but I'd like to get it to compile first
};
std::unordered_map<cv::Vec3b, int, decltype(hasher)> color_counts(10, hasher);
I noticed sometimes this happens when headers are not included. These are the included headers:
#include <unordered_map>
#include <functional>
#include "opencv2/core/core.hpp"
Note: I use the same technique for a comparator for priority queues in VS 2013, and it works. I see there's an alternative using std::function but I'd like to make this method work.
EDIT: Complete error log
error C3497: you cannot construct an instance of a lambda
2> E:\Program Files (x86)\Microsoft Visual Studio 12.0\VC\include\xhash(164) : while compiling class template member function 'OSLSegmentation::read_images::<lambda_52090ebe4a9b9afa82eb49e6ee9eb824> std::_Hash_oper1<false,_Hasher>::_Gethash(void) const'
2> with
2> [
2> _Hasher=OSLSegmentation::read_images::<lambda_52090ebe4a9b9afa82eb49e6ee9eb824>
2> ]
2> E:\Program Files (x86)\Microsoft Visual Studio 12.0\VC\include\xhash(242) : see reference to function template instantiation 'OSLSegmentation::read_images::<lambda_52090ebe4a9b9afa82eb49e6ee9eb824> std::_Hash_oper1<false,_Hasher>::_Gethash(void) const' being compiled
2> with
2> [
2> _Hasher=OSLSegmentation::read_images::<lambda_52090ebe4a9b9afa82eb49e6ee9eb824>
2> ]
2> E:\Program Files (x86)\Microsoft Visual Studio 12.0\VC\include\xhash(198) : see reference to class template instantiation 'std::_Hash_oper1<false,_Hasher>' being compiled
2> with
2> [
2> _Hasher=OSLSegmentation::read_images::<lambda_52090ebe4a9b9afa82eb49e6ee9eb824>
2> ]
2> E:\Program Files (x86)\Microsoft Visual Studio 12.0\VC\include\xhash(220) : see reference to class template instantiation 'std::_Hash_oper2<false,_Hasher,_Keyeq>' being compiled
2> with
2> [
2> _Hasher=OSLSegmentation::read_images::<lambda_52090ebe4a9b9afa82eb49e6ee9eb824>
2> , _Keyeq=std::equal_to<cv::Vec3b>
2> ]
2> E:\Program Files (x86)\Microsoft Visual Studio 12.0\VC\include\unordered_map(23) : see reference to class template instantiation 'std::_Uhash_compare<_Kty,_Hasher,_Keyeq>' being compiled
2> with
2> [
2> _Kty=cv::Vec3b
2> , _Hasher=OSLSegmentation::read_images::<lambda_52090ebe4a9b9afa82eb49e6ee9eb824>
2> , _Keyeq=std::equal_to<cv::Vec3b>
2> ]
2> E:\Program Files (x86)\Microsoft Visual Studio 12.0\VC\include\xhash(255) : see reference to class template instantiation 'std::_Umap_traits<_Kty,_Ty,std::_Uhash_compare<_Kty,_Hasher,_Keyeq>,_Alloc,false>' being compiled
2> with
2> [
2> _Kty=cv::Vec3b
2> , _Ty=int
2> , _Hasher=OSLSegmentation::read_images::<lambda_52090ebe4a9b9afa82eb49e6ee9eb824>
2> , _Keyeq=std::equal_to<cv::Vec3b>
2> , _Alloc=std::allocator<std::pair<const cv::Vec3b,int>>
2> ]
2> E:\Program Files (x86)\Microsoft Visual Studio 12.0\VC\include\unordered_map(81) : see reference to class template instantiation 'std::_Hash<std::_Umap_traits<_Kty,_Ty,std::_Uhash_compare<_Kty,_Hasher,_Keyeq>,_Alloc,false>>' being compiled
2> with
2> [
2> _Kty=cv::Vec3b
2> , _Ty=int
2> , _Hasher=OSLSegmentation::read_images::<lambda_52090ebe4a9b9afa82eb49e6ee9eb824>
2> , _Keyeq=std::equal_to<cv::Vec3b>
2> , _Alloc=std::allocator<std::pair<const cv::Vec3b,int>>
2> ]
2> oslsegmentation.cpp(42) : see reference to class template instantiation 'std::unordered_map<cv::Vec3b,int,OSLSegmentation::read_images::<lambda_52090ebe4a9b9afa82eb49e6ee9eb824>,std::equal_to<_Kty>,std::allocator<std::pair<const _Kty,_Ty>>>' being compiled
2> with
2> [
2> _Kty=cv::Vec3b
2> , _Ty=int
2> ]
What am I doing wrong here?

Figured it out after Kerrek's comment:
change this:
auto hasher = [&](const cv::Vec3b& color) -> size_t {
std::hash<int> int_hasher;
return int_hasher(color[0]) + int_hasher(color[1]) + int_hasher(color[2]);
// the above code is probably a wrong way of constructing a hash,
// but I'd like to get it to compile first
};
to (note the reference):
auto& hasher = [&](const cv::Vec3b& color) -> size_t {
std::hash<int> int_hasher;
return int_hasher(color[0]) + int_hasher(color[1]) + int_hasher(color[2]);
// the above code is probably a wrong way of constructing a hash,
// but I'd like to get it to compile first
};

Related

C++ using template type with unordered map

I am new to C++ so this is likely a simple mistake but this code is giving me problems for hours now. I am really just not sure what to try next.
EratosthenesHashMap.h
#pragma once
#include <unordered_map>
#include <boost/functional/hash.hpp>
#include "SieveOfEratosthenes.h"
template<class T>
class EratosthenesHashMap
{
public:
EratosthenesHashMap(SieveOfEratosthenes& sieve);
~EratosthenesHashMap();
unsigned int addValue(T& value);
unsigned int getPrime(T& value) const;
private:
SieveOfEratosthenes *sieve;
std::unordered_map<T, unsigned int, boost::hash<T>> valueMap;
};
EratosthenesHashMap.cpp
#include "EratosthenesHashMap.h"
EratosthenesHashMap<class T>::EratosthenesHashMap(SieveOfEratosthenes& sieve)
{
this->sieve = &sieve;
};
unsigned int EratosthenesHashMap<T>::addValue(T& value)
{
return 0;
}
unsigned int EratosthenesHashMap<T>::getPrime(T& value) const
{
return 0;
}
Error:
EratosthenesHashMap.cpp
1>C:\Program Files (x86)\Microsoft Visual Studio\2019\Community\VC\Tools\MSVC\14.29.30037\include\utility(331,10): error C2079: 'std::pair<const T,unsigned int>::first' uses undefined class 'T'
1> with
1> [
1> T=T
1> ]
1>C:\Program Files (x86)\Microsoft Visual Studio\2019\Community\VC\Tools\MSVC\14.29.30037\include\xhash(305): message : see reference to class template instantiation 'std::pair<const T,unsigned int>' being compiled
1> with
1> [
1> T=T
1> ]
1>C:\Program Files (x86)\Microsoft Visual Studio\2019\Community\VC\Tools\MSVC\14.29.30037\include\xhash(304): message : while compiling class template member function 'void std::_Hash_vec<std::allocator<std::_List_unchecked_iterator<std::_List_val<std::_List_simple_types<_Ty>>>>>::_Tidy(void) noexcept'
1> with
1> [
1> _Ty=std::pair<const T,unsigned int>
1> ]
1>C:\Program Files (x86)\Microsoft Visual Studio\2019\Community\VC\Tools\MSVC\14.29.30037\include\xhash(313): message : see reference to function template instantiation 'void std::_Hash_vec<std::allocator<std::_List_unchecked_iterator<std::_List_val<std::_List_simple_types<_Ty>>>>>::_Tidy(void) noexcept' being compiled
1> with
1> [
1> _Ty=std::pair<const T,unsigned int>
1> ]
1>C:\Program Files (x86)\Microsoft Visual Studio\2019\Community\VC\Tools\MSVC\14.29.30037\include\xhash(1933): message : see reference to class template instantiation 'std::_Hash_vec<std::allocator<std::_List_unchecked_iterator<std::_List_val<std::_List_simple_types<_Ty>>>>>' being compiled
1> with
1> [
1> _Ty=std::pair<const T,unsigned int>
1> ]
1>C:\Program Files (x86)\Microsoft Visual Studio\2019\Community\VC\Tools\MSVC\14.29.30037\include\unordered_map(69): message : see reference to class template instantiation 'std::_Hash<std::_Umap_traits<_Kty,_Ty,std::_Uhash_compare<_Kty,_Hasher,_Keyeq>,_Alloc,false>>' being compiled
1> with
1> [
1> _Kty=T,
1> _Ty=unsigned int,
1> _Hasher=boost::hash<T>,
1> _Keyeq=std::equal_to<T>,
1> _Alloc=std::allocator<std::pair<const T,unsigned int>>
1> ]
1>C:\Users\jpsie\source\repos\EratosthenesContainer\EratosthenesContainer\EratosthenesHashMap.h(20): message : see reference to class template instantiation 'std::unordered_map<T,unsigned int,boost::hash<T>,std::equal_to<T>,std::allocator<std::pair<const T,unsigned int>>>' being compiled
1> with
1> [
1> T=T
1> ]
I am trying to create a hashmap as a member variable with key type T, value type unsigned int, and I am using the boost library for a hash function.
It is rather difficult to have a template class split between header file and .cpp file and be easy to consume by callers. Instead, inline your entire template class in EratosthenesHashMap.h:
template<class T>
class EratosthenesHashMap
{
public:
EratosthenesHashMap(SieveOfEratosthenes& sieve)
{
this->sieve = &sieve;
}
~EratosthenesHashMap()
{
}
unsigned int addValue(T& value)
{
return 0;
}
unsigned int getPrime(T& value) const
{
return 0;
}
private:
SieveOfEratosthenes* sieve;
std::unordered_map<T, unsigned int, boost::hash<T>> valueMap;
};
The way to define a member of a template class is
template<class T>
EratosthenesHashMap<T>::EratosthenesHashMap(SieveOfEratosthenes& sieve)
{
this->sieve = &sieve;
};
On top of that, you should probably defined the templates in the header file, because otherwise they will only be usable in the same cpp file.
See Why can templates only be implemented in the header file?
The reason your code doesn't compile is that you can't break a class template into a .h file and .cpp file in the typical way.
Say you have a main.cpp file that uses EratosthenesHashMap<int> and you have EratosthenesHashMap broken into a .h and a .cpp as in your question, then main.cpp gets compiled completely independently of EratosthenesHashMap.cpp and needs to be able to link to an implementation of EratosthenesHashMap<int> but EratosthenesHashMap.cpp does not know anything about what types it will be applied to so this is impossible.
EratosthenesHashMap.cpp does not define a class; it defines a template; it can't be compiled into an object file that can be linked against.
Typically you use templates by providing a full implementation in a header for this reason.

"error C2678: binary '=' : no operator found which takes a left-hand operand of type..." when using lambda function for map filtering

I have written (partailly copied :) ) the following code:
HigherOrderFunctions.h :
#ifndef HigherOrderFunctions_H
#define HigherOrderFunctions_H
#include <algorithm>
class HigherOrderFunctions {
public:
template<class Coll, class Func>
static Coll& filter(Coll& items, Func&& filterFunc);
private:
HigherOrderFunctions() {}
};
template < class Coll, class Func>
Coll& HigherOrderFunctions::filter(Coll& items, Func&& filterFunc) {
auto first = std::find_if_not(items.begin(), items.end(), filterFunc);
const auto last = items.end();
if (first != last) {
for(auto it = first; ++it != last; ) {
if (filterFunc(*it)) {
*first++ = std::move(*it);
}
}
}
items.erase(first, items.end());
return items;
}
#endif // HigherOrderFunctions_H
Now when I try to test the above code with the test function:
void HighOrderFunctionsTest::testFilter() {
vector<int> integers = {1, 2, 3, 4, 5, 6, 7};
HigherOrderFunctions::filter(integers, [](int elem) -> bool {
return (elem % 2) == 0;
});
const int ADULT_AGE = 18;
map<string, int> name_age_list = {{"sm", 10}, {"ak", 20}, {"al", 30}, {"am", 35}};
function<bool(const pair<string, int>&)> funct = [ADULT_AGE](const pair<string, int>& elem) -> bool {
return (elem.second > ADULT_AGE);
};
HigherOrderFunctions::filter(name_age_list, funct);
}
The part where I filter the vector compiles OK, but when I add the part with map I get the following compile error (using MSVS 2013):
HighOrderFunctionsTest.cpp
2>C:\winapp\MSVS2013PRO\VC\include\utility(175): error C2678: binary '=' : no operator found which takes a left-hand operand of type 'const std::string' (or there is no acceptable conversion)
2> C:\winapp\MSVS2013PRO\VC\include\xstring(1017): could be 'std::basic_string<char,std::char_traits<char>,std::allocator<char>> &std::basic_string<char,std::char_traits<char>,std::allocator<char>>::operator =(_Elem)'
2> with
2> [
2> _Elem=char
2> ]
2> C:\winapp\MSVS2013PRO\VC\include\xstring(1012): or 'std::basic_string<char,std::char_traits<char>,std::allocator<char>> &std::basic_string<char,std::char_traits<char>,std::allocator<char>>::operator =(const _Elem *)'
2> with
2> [
2> _Elem=char
2> ]
2> C:\winapp\MSVS2013PRO\VC\include\xstring(996): or 'std::basic_string<char,std::char_traits<char>,std::allocator<char>> &std::basic_string<char,std::char_traits<char>,std::allocator<char>>::operator =(const std::basic_string<char,std::char_traits<char>,std::allocator<char>> &)'
2> C:\winapp\MSVS2013PRO\VC\include\xstring(957): or 'std::basic_string<char,std::char_traits<char>,std::allocator<char>> &std::basic_string<char,std::char_traits<char>,std::allocator<char>>::operator =(std::initializer_list<_Elem>)'
2> with
2> [
2> _Elem=char
2> ]
2> C:\winapp\MSVS2013PRO\VC\include\xstring(901): or 'std::basic_string<char,std::char_traits<char>,std::allocator<char>> &std::basic_string<char,std::char_traits<char>,std::allocator<char>>::operator =(std::basic_string<char,std::char_traits<char>,std::allocator<char>> &&) throw()'
2> while trying to match the argument list '(const std::string, const std::string)'
2> C:\winapp\MSVS2013PRO\VC\include\utility(174) : while compiling class template member function 'std::pair<const _Kty,_Ty> &std::pair<const _Kty,_Ty>::operator =(std::pair<const _Kty,_Ty> &&)'
2> with
2> [
2> _Kty=std::string
2> , _Ty=int
2> ]
2> D:\tax\tax_win\tc\src\cpp\foundation\HigherOrderFunctions.h(219) : see reference to function template instantiation 'std::pair<const _Kty,_Ty> &std::pair<const _Kty,_Ty>::operator =(std::pair<const _Kty,_Ty> &&)' being compiled
2> with
2> [
2> _Kty=std::string
2> , _Ty=int
2> ]
2> ..\..\..\..\..\..\src\cpp\foundation\test\HighOrderFunctionsTest.cpp(33) : see reference to class template instantiation 'std::pair<const _Kty,_Ty>' being compiled
2> with
2> [
2> _Kty=std::string
2> , _Ty=int
2> ]
I have looked for similar errors and I found out that this could happen if my function where the code is called would be const, but it is not. Can you please help me with this problem?
The problem is cause by *first++ = std::move(*it); line. When container is a map then stored items will be of type pair<const Key, Value>. De-referencing iterator will yield a reference to such a type and any attempt to perform move assignment to it will fail because the value of Key can not be changed.
I think the key issue with this code is that filter function is supposed to produce a new container with filtered values, not mutate supplied container. Currently implemented algorithm seems to be working similar to std::remove_if.

Strange compiler messages when using lambdas in C++

So I've added the use of lambdas in a C++ project and now the compiler is giving output like this:
9>C:\Program Files (x86)\Microsoft Visual Studio 10.0\VC\include\xxcallobj(13): warning C4800: 'BOOL' : forcing value to bool 'true' or 'false' (performance warning)
3> C:\Program Files (x86)\Microsoft Visual Studio 10.0\VC\include\xxfunction(386) : see reference to class template instantiation 'std::tr1::_Impl_no_alloc0<_Callable,_Rx>' being compiled
3> with
3> [
3> _Callable=_MyWrapper,
3> _Rx=bool
3> ]
3> C:\Program Files (x86)\Microsoft Visual Studio 10.0\VC\include\xxfunction(369) : see reference to function template instantiation 'void std::tr1::_Function_impl0<_Ret>::_Reset0o<_Myimpl,_Fty,std::allocator<_Ty>>(_Fty,_Alloc)' being compiled
3> with
3> [
3> _Ret=bool,
3> _Fty=`anonymous-namespace'::<lambda3>,
3> _Ty=std::tr1::_Function_impl0<bool>,
3> _Alloc=std::allocator<std::tr1::_Function_impl0<bool>>
3> ]
3> C:\Program Files (x86)\Microsoft Visual Studio 10.0\VC\include\functional(113) : see reference to function template instantiation 'void std::tr1::_Function_impl0<_Ret>::_Reset<_Fx>(_Fty)' being compiled
3> with
3> [
3> _Ret=bool,
3> _Fx=`anonymous-namespace'::<lambda3>,
3> _Fty=`anonymous-namespace'::<lambda3>
3> ]
3> ..\..\Common\IOFile.cpp(1162) : see reference to function template instantiation 'std::tr1::function<_Fty>::function<`anonymous-namespace'::<lambda3>>(_Fx)' being compiled
3> with
3> [
3> _Fty=bool (void),
3> _Fx=`anonymous-namespace'::<lambda3>
3> ]
And the code for my lambda is:
In the .h:
typedef std::function<bool ()> RepeatingFunction;
static bool RepeatFileOperation(RepeatingFunction callback);
static bool Copy(CString file, CString copyFileName, bool failIfExists = true);
In the .cpp:
bool IOFile::RepeatFileOperation(RepeatingFunction callback)
{
const int times_to_retry = 10;
bool succeed = false;
// Retry a few times if it doesn't work
int retries = 0;
do
{
// Perform the caller's action on the file
succeed = callback();
}
while (!succeed && retries++ < times_to_retry);
return succeed;
}
bool IOFile::Copy(CString file, CString copyFileName, bool failIfExists)
{
return RepeatFileOperation([&] {
return CopyFile(file, copyFileName, static_cast<BOOL>(failIfExists));
});
}
The program still compiles just fine. I Googled the error and can find people getting similar messages but in their case the program doesn't build. In all cases it appears that their build errors are about forward declaration, but as I said mine builds fine and I'm including <functional> in the header file so it should be able to find it fine.
Are these messages something I should be worried about or are they just expected behaviour?
CopyFile doesn't return a bool, but you are implicitly casting its result to a bool. Just add an explicit cast return static_cast<bool>(CopyFile(...

Cannot instantiate abstract class using c++11

Why can't I use an abstract class like an interface at runtime.
I get the output:
1>c:\program files (x86)\microsoft visual studio 12.0\vc\include\xmemory0(615): error C2259: 'Creature' : cannot instantiate abstract class
1> due to following members:
1> 'std::string Creature::Move(std::vector<std::string,std::allocator<_Ty>> &)' : is abstract
1> with
1> [
1> _Ty=std::string
1> ]
1> visual studio 2013\projects\cpp_demo\cpp_demo\creature.h(9) : see declaration of 'Creature::Move'
1> c:\program files (x86)\microsoft visual studio 12.0\vc\include\xmemory0(614) : while compiling class template member function 'void std::allocator<_Ty>::construct(_Ty *,const _Ty &)'
1> with
1> [
1> _Ty=Creature
1> ]
1> c:\program files (x86)\microsoft visual studio 12.0\vc\include\xmemory0(752) : see reference to function template instantiation 'void std::allocator<_Ty>::construct(_Ty *,const _Ty &)' being compiled
1> with
1> [
1> _Ty=Creature
1> ]
1> c:\program files (x86)\microsoft visual studio 12.0\vc\include\type_traits(580) : see reference to class template instantiation 'std::allocator<_Ty>' being compiled
1> with
1> [
1> _Ty=Creature
1> ]
1> c:\program files (x86)\microsoft visual studio 12.0\vc\include\vector(650) : see reference to class template instantiation 'std::is_empty<_Alloc>' being compiled
1> with
1> [
1> _Alloc=std::allocator<Creature>
1> ]
1> visual studio 2013\projects\cpp_demo\cpp_demo\main.cpp(7) : see reference to class template instantiation 'std::vector<Creature,std::allocator<_Ty>>' being compiled
1> with
1> [
1> _Ty=Creature
1> ]
My code:
int main()
{
unique_ptr<vector<Creature>> pCreatures(new vector<Creature>);
unique_ptr<Creature> pHuman(new Human());
pCreatures->push_back(*pHuman);
}
#include "stdafx.h"
#include "Creature.h"
class Human : public Creature
{
public:
virtual string Move(vector<string> &log);
};
#include "stdafx.h"
#include "IMove.h"
class Creature : public IMove
{
public:
virtual string Move(vector<string> &log) = 0;
virtual string GetState(vector<string> &log);
};
Please help.
You CAN use abstract class in vector or unique_ptr, e.g.
#include <vector>
#include <memory>
using namespace std;
class Interface {
public:
virtual ~Interface() = 0;
};
Interface::~Interface() {}
class Implementation : public Interface {
};
int main(int argc, char** argv) {
unique_ptr<Interface> p(new Implementation);
vector<unique_ptr<Interface>> v;
v.emplace_back(new Implementation);
vector<Interface> vi;
// This leads to compile error: vi.emplace_back();
}
Moreover, you CAN use vector<Interface> as long as you don't call any methods that potentially calls new Interface. For example, if you just declare a variable vector<Interface> v; it compiles, but if you push_back or emplace_back or resize, then it will have compile error because they will call new Interface.
The above code is tested under gcc-4.6.3.
You can use, but instead of using:
unique_ptr<vector<Creature>> pCreatures(new vector<Creature>);
use
vector<unique_ptr<Creature>> pCreatures;
so you will have a vectors of Creatures pointers, managed by unique_ptr.
There are, at least, two ways to use this vector:
Creating the objects directly into the vector:
pCreatures.emplace_back(new Human());
Moving an unique_ptr to it:
unique_ptr pHuman(new Human());
pCreatures.push_back(move(pHuman));
Below is a compact usage:
int main()
{
vector<unique_ptr<Creature>> pCreatures;
pCreatures.emplace_back(new Human());
unique_ptr<Creature> pHuman(new Human());
pCreatures.push_back(move(pHuman));
// example of usage
pCreatures[0]->Move();
}

Sorting a list of objects holding a vector of unique_ptr

Is the following code supposed to produce compilation error according to C++11 (if so why?) or is it a problem with VC11?
#include <vector>
#include <list>
#include <memory>
struct A
{
std::vector<std::unique_ptr<int>> v;
};
int main()
{
std::list<A> l;
l.sort([](const A& a1, const A& a2){ return true; });
}
Visual C++ 2012 produces the following compilation error:
1>c:\program files (x86)\microsoft visual studio 11.0\vc\include\xmemory0(606): error C2248: 'std::unique_ptr<_Ty>::unique_ptr' : cannot access private member declared in class 'std::unique_ptr<_Ty>'
1> with
1> [
1> _Ty=int
1> ]
1> c:\program files (x86)\microsoft visual studio 11.0\vc\include\memory(1447) : see declaration of 'std::unique_ptr<_Ty>::unique_ptr'
1> with
1> [
1> _Ty=int
1> ]
1> c:\program files (x86)\microsoft visual studio 11.0\vc\include\xmemory0(605) : while compiling class template member function 'void std::allocator<_Ty>::construct(_Ty *,const _Ty &)'
1> with
1> [
1> _Ty=std::unique_ptr<int>
1> ]
1> c:\program files (x86)\microsoft visual studio 11.0\vc\include\xmemory0(751) : see reference to function template instantiation 'void std::allocator<_Ty>::construct(_Ty *,const _Ty &)' being compiled
1> with
1> [
1> _Ty=std::unique_ptr<int>
1> ]
1> c:\program files (x86)\microsoft visual studio 11.0\vc\include\type_traits(743) : see reference to class template instantiation 'std::allocator<_Ty>' being compiled
1> with
1> [
1> _Ty=std::unique_ptr<int>
1> ]
1> c:\program files (x86)\microsoft visual studio 11.0\vc\include\vector(655) : see reference to class template instantiation 'std::is_empty<_Ty>' being compiled
1> with
1> [
1> _Ty=std::allocator<std::unique_ptr<int>>
1> ]
1> d:\test2\test2.cpp(213) : see reference to class template instantiation 'std::vector<_Ty>' being compiled
1> with
1> [
1> _Ty=std::unique_ptr<int>
1> ]
It's "a problem with VC", but only because you're misusing Visual Studio.
VC++ implements r-value references, but it does not implement compiler-generated move constructors/assignment operators. Which means that, if you want a type to be moveable, you must write one yourself.
A is not a moveable type, so the various std::list functions will attempt to copy them. And they'll fail when they try to copy a vector of unique_ptr. Hence the compiler error.
If you want move-aware objects in VC++, you must write move constructors/assignments for them yourself.
The problem is really in VC11, as it doesn't implement C++11 feature of automatically generating move operations (as already nailed by Nicol Bolas).
The following code compiles with VC10 SP1; in this code sample, move constructor is explicitly written (instead for move operator=, the copy-and-swap idiom is used).
#include <algorithm> // for std::swap (for copy-and-swap idiom)
#include <list>
#include <memory>
#include <vector>
struct A
{
std::vector<std::unique_ptr<int>> v;
A(A&& other)
: v( std::move(other.v) )
{
}
A& operator=(A other)
{
swap(*this, other);
return *this;
}
friend void swap(A& lhs, A& rhs)
{
using std::swap;
swap(lhs.v, rhs.v);
}
};
int main()
{
std::list<A> l;
l.sort( []( const A& , const A& ){ return true; } );
}
It was an issue with Visual C++ 2012 (acknowledged by Microsoft on Connect: Compile error in C++ code sorting a list of objects holding a vector of unique_ptr) and it was already fixed in Visual C++ 2013.
Also, I'd like to point out that an issue had nothing to do with the fact, that Visual C++ does not implicitly generate move constructors. If you explicitly delete all copy and move constructors in struct A (yes, it will make impossible inserting objects of type A into the list, but that is beside the point) in my original example the code still is not supposed to copy or move any objects and as such produce compilation errors:
#include <vector>
#include <list>
#include <memory>
struct A
{
std::vector<std::unique_ptr<int>> v;
A(A&&) = delete;
A(const A&) = delete;
};
int main()
{
std::list<A> l;
l.sort([](const A& a1, const A& a2){ return true; });
}