Compiler error with boost iterator adaptor - c++

I am trying to write a simple STL iterator for CArray MFC class using boost iterator adaptor. This is my code:
#include <boost/iterator/iterator_adaptor.hpp>
#include <afxtempl.h>
class CArrIter : public boost::iterator_adaptor< CArrIter ,
int,
int,
boost::random_access_traversal_tag >
{
public:
CArrIter(CArray<int,int>& arr, int index = 0) : m_arr(arr)
{
this->base_reference() = index;
}
private:
friend class boost::iterator_core_access;
int dereference() const{
return m_arr.GetAt(base());
}
private:
CArray<int,int>& m_arr;
};
This compiles fine with VC9 compiler. But when I try compiling this with VC7 I get the following error:
\include\boost\iterator\iterator_traits.hpp(49)
: erro r C2039: 'difference_type' : is
not a member of
'boost::detail::iterator_traits<
Iterator>'
with
[
Iterator=int
]
\include\boost\mpl\eval_if.hpp(41) :
see refer ence to class template
instantiation
'boost::iterator_difference'
bein g compiled
with
[
Iterator=int
]
.... Some more ....
Any clues what could be wrong? I have to include some other header files? I am quite new to boost library.

I think that the second template parameter of boost::iterator_adaptor<> has to be a valid iterator type, try using int* instead of int.

It could be related to the random access behavior not having everything it needs to traverse the container. The 'iterator_adaptor requirements' section of this link might help:
Boost: Iterator Adapter
I'm not sure if int is assignable, so I wonder what would happen if you changed int to int&.
A couple more ideas:
Are you using the same version of the Boost library with both compilers?
Does making dereference() protected or public help?

Related

C++11 code using empty initalizer as parmeter compiles in GCC 4.8, 7, Cygwin, but not MSVS 2017

As requested, I have a code file that compiles and runs on cygwin, but not in MSVS where an empty initalizer being used as a parameter to a templated function is okay in gcc, but not MSVS:
// TestError.cpp : Defines the entry point for the console application.
//
#include <iostream>
#include <array>
#include <vector>
template <typename T>
class otherclass
{
public:
T* allocated;
otherclass(int n) { allocated = new T[n]; }
~otherclass() { delete[] allocated; }
};
class otherclass_accessor
{
public:
int sz;
otherclass_accessor(int inputSize) : sz(inputSize) {}
};
template<typename T>
class baseclass : public otherclass_accessor
{
private:
std::vector<T*> mPointers;
public:
T const * const * sp;
std::vector<T> someVector;
baseclass(std::vector<T>& someVector) : otherclass_accessor(someVector) {}
~baseclass() { mPointers.resize(0); }
};
class RRC : public baseclass<int>
{
public:
template <typename T> RRC(otherclass<T>& a) : baseclass<void>(reinterpret_cast<otherclass<void>&>(a)) {}
template< typename T > operator baseclass<T> const & () const { return reinterpret_cast< baseclass<T> const & >(*this); }
};
template< int N > using ARRC = std::array<RRC, N>;
template <int A>
void run_filter_multi(ARRC<A> in)
{
std::cout << "Input Size:" << in.size() << std::endl;
}
int main()
{
run_filter_multi<0>({});
return 0;
}
compiles with g++ -std=c++11 TestError.cpp -o test
and outputs:
Input Size:0
but with MSVS2017 I get error C2664:
1>------ Build started: Project: TestError, Configuration: Debug Win32 ------
1>TestError.cpp
1>c:\users\dayd\documents\visual studio 2017\projects\testerror\testerror.cpp(53): error C2664: 'void run_filter_multi<0>(std::array)': cannot convert argument 1 from 'initializer list' to 'std::array'
1>c:\users\dayd\documents\visual studio 2017\projects\testerror\testerror.cpp(53): note: Invalid aggregate initialization
1>Done building project "TestError.vcxproj" -- FAILED.
========== Build: 0 succeeded, 1 failed, 0 up-to-date, 0 skipped ==========
So - now my question is why is an empty initializer okay with g++, but not MSVS2017? This is a watered down version where I tried to mock up what I was experiencing in a much larger project I am trying to make "cross platform". I can't seem to think of a way around it in MSVS. I have tried using std::vector instead of std::array, but the std::array is so pervasive in the code I inherited that trying to change all the underlying layers would be very painful, at best.
Thanks!
There are a few issues, but the big show-stopper one is this:
#include <array>
struct S { S(int); }; // Not default-constructible.
std::array<S, 0> x {};
This fails with
error C2073: 'std::array<S,0>::_Elems': elements of partially initialized array must have a default constructor
Since C++ doesn't allow for zero-length arrays, but std::array<T, 0> is still supposed to work, it must be implemented using a little bit of trickery. Unfortunately MSVC's trickery is broken: it gives it a field of type T[1], which then fails badly because the empty unused T element cannot be constructed.
The only ways around this that I see is giving RRC a default constructor, or avoiding std::array<T, 0>.

c++ unordered_multimap insert hash

I'm going crazy over here. I have search google to find 1 single decent example where people use a unordered_map together with enum class and a hash function without any luck. Those i manage to find always end up saying "use map instead".
I'm trying to do the following:
Enum class facing is the direction my sprite is looking at.
Enum class Action is the action my sprite is doing.
Animation is a class that holds different animations which i will call later.
The container should look like this:
map
There can be more than 1 FACING in the map as key and there can be more than one ACTION in the pair.
Example:
map<LEFT, pair<ATTACK, attackAnimation>
map<LEFT, pair<IDLE, idleAnimation>
map<LEFTUP, pair<IDLE, idleAnimation>
This is an simplified everything
#include <iostream>
#include <unordered_map>
#include <string>
#include <memory>
template <typename T>
struct Hash
{
typedef typename std::underlying_type<T>::type underlyingType;
typedef typename std::hash<underlyingType>::result_type resultType;
resultType operator()(const T& arg) const
{
std::hash<underlyingType> hasher;
return hasher(static_cast<underlyingType>(arg));
}
};
class Animation
{
private:
std::string str;
public:
Animation(std::string _string)
{
this->str = _string;
}
std::string& GetString()
{
return this->str;
}
};
class Bullshit
{
public:
enum class Action
{
Attack,
Move
};
enum class Facing
{
Right,
Up,
Left
};
Bullshit()
{
}
std::unordered_multimap<Bullshit::Facing, std::pair<Bullshit::Action, std::unique_ptr<Animation>>,Hash<Bullshit::Facing>>& GetlistAnimation()
{
return this->listAnimation;
}
private:
std::unordered_multimap<Bullshit::Facing, std::pair<Bullshit::Action, std::unique_ptr<Animation>>,Hash<Bullshit::Facing>> listAnimation;
};
int main()
{
Bullshit bull;
auto myList = bull.GetlistAnimation();
std::unique_ptr<Animation> anim(new Animation("test"));
myList.insert(std::make_pair(Bullshit::Facing::Up, std::make_pair(Bullshit::Action::Attack, std::move(anim))));
std::cin.get();
return 0;
}
Error code:
error C2248: 'std::unique_ptr<_Ty>::unique_ptr' : cannot access private member declared in class 'std::unique_ptr<_Ty>'
1> with
1> [
1> _Ty=Animation
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=Animation
1> ]
1> This diagnostic occurred in the compiler generated function 'std::pair<_Ty1,_Ty2>::pair(const std::pair<_Ty1,_Ty2> &)'
1> with
1> [
1> _Ty1=Bullshit::Action,
1> _Ty2=std::unique_ptr<Animation>
1> ]
Here
auto myList = bull.GetlistAnimation();
the type deduced for myList is std::unordered_map<.....>, that is, it's not a reference. And the copy can't be created because the map contains unique_ptrs. What you meant is
auto& myList = bull.GetlistAnimation();
or in C++14,
decltype(auto) myList = bull.GetlistAnimation();
The problem has nothing to do with unordered_map or hash functions. It's the std::unique_ptr, which is uncopyable, and your GetlistAnimation attempts to copy it (indirectly).
How to correctly fix this depends on what you want to achieve.
A quick fix would be to use std::shared_ptr instead:
std::unordered_map<Bullshit::Facing, std::pair<Bullshit::Action, std::shared_ptr<Animation>>,Hash<Bullshit::Facing>>& GetlistAnimation()
{
return this->listAnimation;
}
private:
std::unordered_map<Bullshit::Facing, std::pair<Bullshit::Action, std::shared_ptr<Animation>>,Hash<Bullshit::Facing>> listAnimation;
[...]
std::shared_ptr<Animation> anim(new Animation("test"));
myList.insert(std::make_pair(Bullshit::Facing::Up, std::make_pair(Bullshit::Action::Attack, anim)));
(By the way, you should use std::make_shared and std::make_unique.)
A fix which may be quick and correct (again, depending on what you want to achieve) is to get rid of the pointer logic altogether and just use Animation directly:
std::unordered_map<Bullshit::Facing, std::pair<Bullshit::Action, Animation>,Hash<Bullshit::Facing>>& GetlistAnimation()
{
return this->listAnimation;
}
private:
std::unordered_map<Bullshit::Facing, std::pair<Bullshit::Action, Animation>,Hash<Bullshit::Facing>> listAnimation;
[...]
Animation anim("test");
myList.insert(std::make_pair(Bullshit::Facing::Up, std::make_pair(Bullshit::Action::Attack, anim)));

Error C2888 migrating from VC9 to VC10

I am trying to compile solutions and projects on MSVC++ 10 that worked fine in MSVC++ 9, and I am having trouble with it, mostly getting the following message:
error C2888: 'std::hash' : symbol cannot be defined within namespace 'tr1'
on the following code:
namespace std {
namespace tr1 {
template <>
struct hash< Rubedo::eChannelFamily >
{
std::size_t operator()( const Rubedo::eChannelFamily& Key ) const
{
return ( int ) Key;
}
};
}}
I would be perfectly happy if I could do one of the following:
Modify the code to fix the bugs and compile cleanly;
Force the compiler to behave like MSVC++ 9.0.
How would I do something like that?
Thank you very much in advance.
hash is in namespace std in VS2010, as it's part of C++0x's Standard library, not std::tr1. Just remove the tr1 section and the compiler should be fine.
template<> class std::hash< Rubedo::eChannelFamily >>
: public std::unary_function<const Rubedo::eChannelFamily, size_t>
{
public:
size_t operator()(const Rubedo::eChannelFamily& ref) const {
return ( int ) ref;
}
};
This is a fairly trivial modification of a hash I have for my own type which compiles successfully.
You've to inherit unary_function like this and tr1 is not needed anymore,
namespace std
{
template <>
struct hash<Rubedo::eChannelFamily> : public unary_function<Rubedo::eChannelFamily, size_t>
{
size_t operator()(const Rubedo::eChannelFamily& key) const
{
return (size_t) key;
}
};
}

How can I fix my Factory Pattern to eradicate these compile errors?

My goal is to create a system wherein I can provide the string name of an class at run time and have it return an instance of that class in turn.
Searching stackoverflow, I came across an example that seems to do exactly what I am trying to accomplish, although I am currently unable to have it compile properly. The following is based on that code:
//LevelObject.h
#pragma once
#include <map>
#include <string>
class LevelObject
{
protected:
int ID;
public:
template<class T> static LevelObject* createT(void)
{
return new T(0);
}
LevelObject(void);
~LevelObject(void);
};
struct BaseFactory
{
typedef std::map<std::string, LevelObject*(*)()> map_type;
static LevelObject* createInstance(const std::string& s)
{
map_type::iterator it = getMap()->find(s);
if(it == getMap()->end())
{
return 0;
}
return it->second();
}
private:
static map_type* objectMap;
protected:
static map_type* getMap()
{
if(!objectMap)
{
objectMap= new map_type;
}
return objectMap;
}
};
template<class T>
struct DerivedRegister : BaseFactory
{
DerivedRegister(const std::string& s)
{
getMap()->insert(std::make_pair( s, &LevelObject::createT<T> ));
}
};
//Item.h
#pragma once
#include "LevelObject.h"
class Item :
public LevelObject
{
int ID;
static DerivedRegister<Item> reg;
public:
Item(int id);
~Item(void);
};
//Item.cpp
#include "Item.h"
Item::Item(int id)
{
ID = id;
}
Item::~Item(void)
{
}
DerivedRegister<Item> Item::reg("item");
The logic is that the derived objects, i.e. Item, will register a string and reference to a function that returns an instance of itself. On calling createInstance, it will take in a user inputted string and use the map to determine the object to return.
Unfortunately, this code is not compiling correctly, and gives me the following errors:
Error 1 error C2752:
'std::tr1::_Remove_reference<_Ty>' :
more than one partial specialization
matches the template argument list
Error 2 error C2528: 'abstract
declarator' : pointer to reference is
illegal c:\program files\microsoft
visual studio
10.0\vc\include\type_traits 965
Error 3 error C2528: 'type' : pointer
to reference is illegal c:\program
files\microsoft visual studio
10.0\vc\include\type_traits 349
If someone can help smooth out these errors, I would greatly appreciate it.
Or perhaps I am going about this entirely wrong in the first place, so if someone instead feels that I should be going in a different direction entirely please let me know.
Thanks in advance.
It's been a long time since this question was posted, but since there's no answer and I stumbled here too, I figured I'd add one. I copied the same factory code you did (from the StackOverflow answer here) and had the same problem. I found the solution at this StackOverflow answer.
It turns out Visual Studio 2010 (which I'm assuming you're using) has a problem with std::make_pair. Just use std::pair<std::string,LevelObject*(*)()> instead and you'll be good to go. At least that resolved this exact same problem for me.
I added empty bodies to the LevelObject class constructor and destructor:
LevelObject(void) { }
~LevelObject(void) { }
Then declared the static map member variable of the BaeFactory class:
BaseFactory::map_type* BaseFactory::map;
and the code compiled without errors in both GCC and Visual Studio.

BOOST_FOREACH: What is the error on using this of a STL container?

Does anyone know why the following generates an error on VC9?
class Elem;
class ElemVec : public vector<Elem>
{
public:
void foo();
};
void ElemVec::foo()
{
BOOST_FOREACH(Elem& elem, *this)
{
// Do something with elem
}
return;
}
The error I get is:
error C2355: 'this' : can only be referenced inside non-static member functions
The only (hack) solution I have right now which compiles without error is:
void ElemVec::foo()
{
ElemVec* This = this;
BOOST_FOREACH(Elem& elem, *This)
{
// Do something with elem
}
return;
}
You shouldn't inherit from STL containers. These are not polymorphic classes and it's the reason BOOST_FORACH can't handle your derived class.
Try to use aggregation instead.
Which compiler/Boost version are you using? I can compile the following without any problem (VS2005/Boost 1.38):
#include <boost/foreach.hpp>
using namespace std;
struct xxx : std::vector<int>
{
void test()
{
BOOST_FOREACH(int x, *this)
{
}
}
};
int main(void) {
xxx x;
x.test();
return 0;
}
Search the Boost bugbase if you want more details.
I had never seen that error. I guess it comes from the implementation of BOOST_FOREACH macro.
May i ask why you're creating a class based on vector<...> and not having a vector member variable ?
EDIT
Following this thread, i found out that this actually is a visual studio bug. The solution you have found seems to be the simplest.
Hmm, all compiled succesfully on my msvc (2005) compiller.
Maybe you have some error, but fixed or avoided it when was created your example.