Storing containers in a boost::variant - c++

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>.

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.

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

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

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.

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.