l-value specifies const object while using std::map - c++

I'm trying to use std::map like in example below:
#include <map>
#include <algorithm>
int wmain(int argc, wchar_t* argv[])
{
typedef std::map<int, std::wstring> TestMap;
TestMap testMap;
testMap.insert(std::make_pair(0, L"null"));
testMap.insert(std::make_pair(1, L"one"));
testMap.erase(std::remove_if(testMap.begin(), testMap.end(), [&](const TestMap::value_type& val){ return !val.second.compare(L"one"); }), testMap.end());
return 0;
}
And my compiler (VS2010) gives me following message:
>c:\program files\microsoft visual studio 10.0\vc\include\utility(260): error C2166: l-value specifies const object
1> c:\program files\microsoft visual studio 10.0\vc\include\utility(259) : while compiling class template member function 'std::pair<_Ty1,_Ty2> &std::pair<_Ty1,_Ty2>::operator =(std::pair<_Ty1,_Ty2> &&)'
1> with
1> [
1> _Ty1=const int,
1> _Ty2=std::wstring
1> ]
1> e:\my examples\с++\language tests\maptest\maptest\maptest.cpp(8) : see reference to class template instantiation 'std::pair<_Ty1,_Ty2>' being compiled
1> with
1> [
1> _Ty1=const int,
1> _Ty2=std::wstring
1> ]
I can't understand why opertor = is called though I pass val in lambda-function by reference.
Could you explain what I am doing wrong?

You cannot use std::remove_if with an associative container, because that algorithm works by overwriting removed elements with the subsequent ones: the problem here is that keys of a map are constant, in order to prevent you (or the std::remove_if algorithm) from messing up with the internal ordering of the container.
To remove elements from a map conditionally, rather do this:
for (auto iter = testMap.begin(); iter != testMap.end();)
{
if (!iter->second.compare(L"one")) // Or whatever your condition is...
{
testMap.erase(iter++);
}
else
{
++iter;
}
}
Here is a live example.

Related

Sort a 2D character Array using sort() in C++

I have a 2D character array (I don't want to use array of std::string). How can I sort the strings (char*) in ascending order according to the length of the string using std::sort()?
I have tried the following. But it doesn't work.
char names[100][30];
bool comp(const char* a, const char* b){
return strlen(a)<strlen(b);
}
int main(){
...
//I want to sort the first n strings
sort(names,names+n,comp); //n<=100
...
}
I have found these errors:
1>e:\program files (x86) in e\microsoft visual studio 9.0\vc\include\algorithm(3128) : error C2075: '_Val' : array initialization needs curly braces
1> e:\program files (x86) in e\microsoft visual studio 9.0\vc\include\algorithm(3150) : see reference to function template instantiation 'void std::_Insertion_sort1<_BidIt,bool(__cdecl *)(const char *,const char *),char[30]>(_BidIt,_BidIt,_Pr,_Ty (*))' being compiled
1> with
1> [
1> _BidIt=char (*)[30],
1> _Pr=bool (__cdecl *)(const char *,const char *),
1> _Ty=char [30]
1> ]
1> e:\program files (x86) in e\microsoft visual studio 9.0\vc\include\algorithm(3270) : see reference to function template instantiation 'void std::_Insertion_sort<_RanIt,bool(__cdecl *)(const char *,const char *)>(_BidIt,_BidIt,_Pr)' being compiled
1> with
1> [
1> _RanIt=char (*)[30],
1> _BidIt=char (*)[30],
1> _Pr=bool (__cdecl *)(const char *,const char *)
1> ]
1> e:\program files (x86) in e\microsoft visual studio 9.0\vc\include\algorithm(3279) : see reference to function template instantiation 'void std::_Sort<char(*)[30],int,bool(__cdecl *)(const char *,const char *)>(_RanIt,_RanIt,_Diff,_Pr)' being compiled
1> with
1> [
1> _RanIt=char (*)[30],
1> _Diff=int,
1> _Pr=bool (__cdecl *)(const char *,const char *)
1> ]
1> e:\projects visual studio2008\sample\sample\sorting.cpp(51) : see reference to function template instantiation 'void std::sort<char(*)[30],bool(__cdecl *)(const char *,const char *)>(_RanIt,_RanIt,_Pr)' being compiled
1> with
1> [
1> _RanIt=char (*)[30],
1> _Pr=bool (__cdecl *)(const char *,const char *)
1> ]
1>e:\program files (x86) in e\microsoft visual studio 9.0\vc\include\algorithm(3133) : error C2106: '=' : left operand must be l-value
1>e:\program files (x86) in e\microsoft visual studio 9.0\vc\include\algorithm(3140) : error C2106: '=' : left operand must be l-value
1>e:\program files (x86) in e\microsoft visual studio 9.0\vc\include\algorithm(3141) : error C2106: '=' : left operand must be l-value
1>Build log was saved at "file://e:\projects visual studio2008\sample\sample\Debug\BuildLog.htm"
1>sample - 4 error(s), 3 warning(s)
========== Build: 0 succeeded, 1 failed, 0 up-to-date, 0 skipped ==========
If your data is in
char names[100][30];
then you cannot sort "the pointers" because that data structure has no pointers at all... just 100*30 = 3000 characters one after another.
Therefore to do the sorting you will need to actually move around the 100 rows will all their content.
std::sort cannot be used directly because the data structure is an array of arrays, and arrays are in C++ second-class citizens (for example you cannot assign an array to another).
std::sort requires that its iterator type parameter must be:
ValueSwappable and RandomAccessIterator.
The type of dereferenced iterator type must meet the requirements of:
MoveAssignable and MoveConstructible.
Unfortunately, arrays are not swappable (i.e., you cannot assign one to the other). Consequently, you can't use std::sort with arrays.
What you can do is use std::array<std::array<char, N>, M> in the following manner:
template<std::size_t N, std::size_t M>
void custom_sort(std::array<std::array<char, M>, N> &arrs) {
std::sort(std::begin(arrs), std::end(arrs), [](auto const &a, auto const &b){ return strnlen(a.data(), M) < strnlen(b.data(), M); });
}
LIVE DEMO
Impovements to code thanks to #Jarod42
As already mentioned, arrays can't be assigned. Structures can be assigned, so this might be close to what you want. The array of structures might be padded for alignment. In the case of Visual Studio 2015, the array of structures was not padded, so the memory layout was the same as a 2d array.
update - changed to using references for compare parameters and switched to strnlen as suggested by Jarod42.
#include <algorithm>
#include <cstring>
using namespace std;
typedef struct
{
char name[30];
}name;
name names[4] = { { "12345678" },{ "123" },{ "12345" },{ "12" } };
bool comp(const name &a, const name &b)
{
return strnlen(a.name,30) < strnlen(b.name,30);
}
int main(){
sort(names, names+4, comp);
return 0;
}
You can try this:
#include <stdlib.h>
#include <stdio.h>
#include <string.h>
#define M 10000
int main()
{
char names[M][15];
int n, i;
scanf("%d", &n);
for (i = 0; i < n; i++)
scanf("%s", names[i]);
qsort(names, n, 15, (int (*)(const void *, const void *))strcmp);
for(i = 0; i < n; i++)
printf("%s\n", names[i]);
}

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; });
}

Storing containers in a boost::variant

The last line here:
typedef boost::variant<std::vector<int>, std::vector<float>> C;
class A: public boost::static_visitor<>
{
public:
void operator()(const std::vector<int>& value) const
{
}
void operator()(const std::vector<float>& value) const
{
}
};
C container(std::vector<float>());
boost::apply_visitor(A(), container );
Is giving me the error:
c:\boost_1_49_0\boost\variant\detail\apply_visitor_unary.hpp(60): error C2228: left of '.apply_visitor' must have class/struct/union
1> type is 'boost::variant<T0_,T1> (__cdecl &)'
1> with
1> [
1> T0_=std::vector<int>,
1> T1=std::vector<float>
1> ]
1> c:\visual studio 2010\projects\db\xxx\main.cpp(255) : see reference to function template instantiation 'void boost::apply_visitor<A,C(std::vector<_Ty> (__cdecl *)(void))>(Visitor &,Visitable (__cdecl &))' being compiled
1> with
1> [
1> _Ty=float,
1> Visitor=A,
1> Visitable=C (std::vector<float> (__cdecl *)(void))
What is the problem here? Is it sensible in you opinion to have a container type C which such a definition?
I am using the following type throughout my code:
typedef boost::variant<int, float, ...> Type;
Do you think it would be wiser to use this container definition instead:
typedef std::vector<Type> C; // mixed container
Why?
Your problem is that this
C container(std::vector<float>());
is a function declaration (that’s the most vexing parse) (a function container which takes a function returning std::vector<float> as its sole argument, and returns C). Easy fix: extra parentheses:
C container((std::vector<float>()));
The fact that you’re using containers in the variant is irrelevant to the problem. The same would have happened with boost::variant<int, float>.

C++: Error C2064 with STL

I'm trying to use STL, but the following doesn't compile. main.cpp:
#include <set>
#include <algorithm>
using namespace std;
class Odp
{
public:
set<int> nums;
bool IsOdd(int i)
{
return i % 2 != 0;
}
bool fAnyOddNums()
{
set<int>::iterator iter = find_if(nums.begin(), nums.end(), &Odp::IsOdd);
return iter != nums.end();
}
};
int main()
{
Odp o;
o.nums.insert(0);
o.nums.insert(1);
o.nums.insert(2);
}
The error is:
error C2064: term does not evaluate to a function taking 1 arguments
1> c:\program files\microsoft visual studio 10.0\vc\include\algorithm(95) : see reference to function template instantiation '_InIt std::_Find_if<std::_Tree_unchecked_const_iterator<_Mytree>,_Pr>(_InIt,_InIt,_Pr)' being compiled
1> with
1> [
1> _InIt=std::_Tree_unchecked_const_iterator<std::_Tree_val<std::_Tset_traits<int,std::less<int>,std::allocator<int>,false>>>,
1> _Mytree=std::_Tree_val<std::_Tset_traits<int,std::less<int>,std::allocator<int>,false>>,
1> _Pr=bool (__thiscall Odp::* )(int)
1> ]
1> main.cpp(20) : see reference to function template instantiation '_InIt std::find_if<std::_Tree_const_iterator<_Mytree>,bool(__thiscall Odp::* )(int)>(_InIt,_InIt,_Pr)' being compiled
1> with
1> [
1> _InIt=std::_Tree_const_iterator<std::_Tree_val<std::_Tset_traits<int,std::less<int>,std::allocator<int>,false>>>,
1> _Mytree=std::_Tree_val<std::_Tset_traits<int,std::less<int>,std::allocator<int>,false>>,
1> _Pr=bool (__thiscall Odp::* )(int)
1> ]
What am I doing wrong?
It needs to be declared static:
static bool IsOdd(int i)
Otherwise, you'd be asking find_if to call an instance method without an instance.
The problem is you are passing a pointer to member function. To call that function you would also need a pointer to this but the find_if doesn't let you to pass it. A solution is to wrap it using a function object, see Boost Bind (http://www.boost.org/doc/libs/1_43_0/libs/bind/bind.html) and Boost Function (http://www.boost.org/doc/libs/1_37_0/doc/html/function.html).
IsOdd does not use the class's internals in any way, so don't make it a member function. Instead, pull it out as a standalone function. Then you can call find_if with &IsOdd.
However, there is a benefit to taking things a step further and defining it as a function object:
#include <functional>
struct IsOdd : public unary_function<int, bool>
{
bool operator()(int i) const { return i % 2 != 0; }
};
Then calling find_if with IsOdd() will inline the code within the find_if loop instead of dereferencing a function pointer and making a function call.