Code compiled in VS2008 doesn't in VS2013, const overloading - c++

Now I'm migrating my project from Visual Studio 2008 to 2013 (with no updates installed), and facing a problem.
I have a sort of Variant type, CData< T>, that has a conversion operators to the contained type T.
template<class T> T& GetValue();
template<class T> const T& GetValue() const;
template<class T> T* GetValuePtr();
template<class T> const T* GetValuePtr() const;
template<class T> operator T&() { return GetValue<T>(); }
template<class T> operator const T&() const { return GetValue<T>(); }
template<class T> operator T*() { return GetValuePtr<T>(); }
template<class T> operator const T*() const { return GetValuePtr<T>(); }
There are methods in a class CDataArray:
CData& Get(int Index) { return At(Index); }
const CData& Get(int Index) const { return operator [](Index); }
template<class T>
T& Get(int Index) { return At(Index).GetValue<T>(); }
template<class T>
const T& Get(int Index) const { return operator [](Index).GetValue<T>(); }
and there is a call to it:
Data::PDataArray SGQuests;
Data::PParams SGQuest = SGQuests->Get(i);
Here, Data::PParams is going to be T.
In VS2008, it seems it used non-const non-template CDataArray::Get(), which returned CData&, and then this CData& was accessed with non-const template operator T&(), finally returning Data::PParams&.
In VS2013, it for some reason uses a const overload and it results in error:
1>PATH_TO_SRC\l1\data\type.h(126): error C2678: binary "=": no operator found that accepts left operand "const Ptr<Data::CParams>" (or there is no acceptable conversion)
1> PATH_TO_SRC\l1\data\ptr.h(29): may be "void Ptr<Data::CParams>::operator =(T *)"
1> with
1> [
1> T=Data::CParams
1> ]
1> PATH_TO_SRC\l1\data\ptr.h(28): or "void Ptr<Data::CParams>::operator =(const Ptr<Data::CParams> &)"
1> trying to match argument list "(const Ptr<Data::CParams>, const Ptr<Data::CParams>)"
1> PATH_TO_SRC\l1\data\type.h(125): compiling member function "void Data::CTypeImpl<T>::Copy(void **,void *const *) const" template class
1> with
1> [
1> T=const Ptr<Data::CParams>
1> ]
1> PATH_TO_SRC\l1\data\data.h(167): "Data::CTypeImpl<T>"
1> with
1> [
1> T=const Ptr<Data::CParams>
1> ]
1> PATH_TO_SRC\l1\data\data.h(97): "T &Data::CData::GetValue<T>(void)"
1> with
1> [
1> T=const Ptr<Data::CParams>
1> ]
1> PATH_TO_SRC\l3\quests\questmanager.cpp(307): "Data::CData::operator const T(void)<const Ptr<Data::CParams>>"
1> with
1> [
1> T=const Ptr<Data::CParams>
1> ]
I translated messages to English manually, so they can slightly differ from original EN compiler messages.
And finally, if I write explicit template argument:
Data::PParams SGQuest = SGQuests->Get<Data::PParams>(i);
It compiles OK.
The questions are:
How VS2013 template argument guessing differs from VS2008 one? Is there any place (standard, article or smth) that clearly explains, why my old code shouldn't compile? Any reference would be appreciated.
How should I write code in that situations? Do I have to write template arguments explicitly now, or just modify member overloads, or install some update?
P.S. Minimal code is available at https://www.dropbox.com/s/zjohnu5v87tyr2c/ConstOverload.zip?dl=0 . Full source code is at
https://code.google.com/p/deusexmachina/source/browse/branches/Dev/DEM/Src

This problem was solved by adding third overload to CData
template<class T> operator const T&() { return GetValue<T>(); }
Original solution is posted in:
Conversion operator error C2678 in VS2013, works in VS2008
Look there for possible further details.

Related

How to fix custom allocator compiling error for std::map on windows?

I tried one here. Code as following:
#include <iostream>
#include <string>
#include <vector>
#include <map>
#include <new>
#include <climits>
namespace test {
template <class T>
inline T* _allocate(ptrdiff_t size, T*) {
std::cout << "_allocate called" << std::endl;
T* tmp = (T*)(::operator new((size_t)(size * sizeof(T))));
if (NULL == tmp) {
std::cerr << "out of memory" << std::endl;
exit(0);
}
return tmp;
}
template <class T>
inline void _deallocate(T* p) {
::operator delete(p);
}
template <class T1, class T2>
inline void _construct(T1* p, const T2& value) {
::new (p) T1(value);
}
template <class T>
inline void _destroy(T* p) {
p->~T();
}
template <class T>
class Allocator {
public:
typedef T value_type;
typedef T* pointer;
typedef const T* const_pointer;
typedef T& reference;
typedef const T& const_reference;
typedef size_t size_type;
typedef ptrdiff_t difference_type;
template <class U>
struct rebind {
typedef Allocator<U> other;
};
pointer allocate(size_type n, const void* hint = 0) { return _allocate((difference_type)n, (pointer)0); }
void deallocate(pointer p, size_type n) { return _deallocate(p); }
void construct(pointer p, const T& value) { _construct(p, value); }
void destroy(pointer p) { _destroy(p); }
pointer address(reference x) { return (pointer)&x; }
const_pointer address(const_reference x) { return (const_pointer)&x; }
size_type max_size() const { return size_type(UINT_MAX / sizeof(T)); }
};
} // namespace test
static std::map<void*, uint64_t, std::less<void*>, test::Allocator<std::pair<void* const, uint64_t>>> global_map;
int main()
{
std::vector<std::string> vec = {
"Hello", "from", "GCC", "!"
};
std::cout << "xxxx " << global_map.size() << std::endl;
}
But it leads to compiling fail on Visual Studio 2019 x86:
Build started...
1>------ Build started: Project: ConsoleApplication1, Configuration: Debug Win32 ------
1>ConsoleApplication1.cpp
1>C:\Program Files (x86)\Microsoft Visual Studio\2019\Enterprise\VC\Tools\MSVC\14.29.30037\include\xtree(1096,27): error C2440: 'static_cast': cannot convert from 'test::Allocator<U>' to 'test::Allocator<U>'
1> with
1> [
1> U=std::_Tree_node<std::pair<void *const ,uint64_t>,void *>
1> ]
1> and
1> [
1> U=std::_Container_proxy
1> ]
1>C:\Program Files (x86)\Microsoft Visual Studio\2019\Enterprise\VC\Tools\MSVC\14.29.30037\include\xtree(1096,27): message : No constructor could take the source type, or constructor overload resolution was ambiguous
1>C:\Program Files (x86)\Microsoft Visual Studio\2019\Enterprise\VC\Tools\MSVC\14.29.30037\include\xtree(1092): message : while compiling class template member function 'std::_Tree<std::_Tmap_traits<_Kty,_Ty,_Pr,_Alloc,false>>::~_Tree(void) noexcept'
1> with
1> [
1> _Kty=void *,
1> _Ty=uint64_t,
1> _Pr=std::less<void *>,
1> _Alloc=test::Allocator<std::pair<void *const ,uint64_t>>
1> ]
1>C:\Program Files (x86)\Microsoft Visual Studio\2019\Enterprise\VC\Tools\MSVC\14.29.30037\include\map(348): message : see reference to function template instantiation 'std::_Tree<std::_Tmap_traits<_Kty,_Ty,_Pr,_Alloc,false>>::~_Tree(void) noexcept' being compiled
1> with
1> [
1> _Kty=void *,
1> _Ty=uint64_t,
1> _Pr=std::less<void *>,
1> _Alloc=test::Allocator<std::pair<void *const ,uint64_t>>
1> ]
1>C:\Program Files (x86)\Microsoft Visual Studio\2019\Enterprise\VC\Tools\MSVC\14.29.30037\include\map(75): message : see reference to class template instantiation 'std::_Tree<std::_Tmap_traits<_Kty,_Ty,_Pr,_Alloc,false>>' being compiled
1> with
1> [
1> _Kty=void *,
1> _Ty=uint64_t,
1> _Pr=std::less<void *>,
1> _Alloc=test::Allocator<std::pair<void *const ,uint64_t>>
1> ]
How to fix it?
Edit:
Found another solution. But do not know why. Code as https://godbolt.org/z/jvscsMx7T
This problem appeard in Visual Studio Debug mode , but solved when switching to Release mode. If it still bothers you, you can report problems to Developer Community.

Export container class with LuaBridge

I want to export SRect and SRectVector from C++ to Lua, but compile fails.
What is the proper way to do it?
Compiler: vs2019, vc++11
OS: Win10 64
Push() meets compile error,
I think the argument is just SRectVector *, why the compiler thinks it is 'std::vector<SRect,std::allocator<_Ty>>'?
class SRect{
public:
int left;
int top;
int right;
int bottom;
SRect(int l, int t, int r, int b)
: left(l)
, top(t)
, right(r)
, bottom(b){}
//...
};
typedef std::vector<SRect> SRectVector;
luabridge::getGlobalNamespace(L)
.beginClass <SRect>("SRect")
.addConstructor <void(*) (int, int, int, int)>()
.addProperty("left", &SRect::left)
//...
.endClass()
.beginClass <SRectVector>("SRectVector")
.addFunction("Push",
std::function <void(SRectVector*, const SRect&)>(
[](SRectVector* vec, const SRect& rc) { (*vec).push_back(rc); }))
//...
.endClass()
.endNamespace();
```
1>E:\Code\include\LuaBridge/detail/TypeList.h(177): error C2664: 'luabridge::detail::TypeListValues<luabridge::detail::TypeList<Param,luabridge::detail::TypeList<const SRect&,luabridge::detail::MakeTypeList<>::Result>>>::TypeListValues(luabridge::detail::TypeListValues<luabridge::detail::TypeList<Param,luabridge::detail::TypeList<const SRect&,luabridge::detail::MakeTypeList<>::Result>>> &&)': cannot convert argument 1 from 'std::vector<SRect,std::allocator<_Ty>>' to 'Head'
1> with
1> [
1> Param=SRectVector *
1> ]
1> and
1> [
1> _Ty=SRect
1> ]
1> and
1> [
1> Head=SRectVector *
1> ]
1>E:\Code\include\LuaBridge/detail/TypeList.h(179): note: No user-defined-conversion operator available that can perform this conversion, or the operator cannot be called
1>E:\Code\include\LuaBridge/detail/TypeList.h(176): note: while compiling class template member function 'luabridge::detail::ArgList<Params,1>::ArgList(lua_State *)'
After more digging, I found the reason. A completed user defined class can be easily exported. But a container pointer not. Compiles OK after I added such code,
namespace LuaBridge
{
template <>
struct Stack <SRectVector*>
{
static void push(lua_State* L, SRectVector* ptr)
{
SRectVector** pp = (SRectVector**)lua_newuserdata(L, sizeof(SRectVector*));
*pp = ptr;
}
static SRectVector* get(lua_State* L, int index)
{
return (SRectVector*)lua_touserdata(L, index);
}
};
}
Or add a more generic one,
template <class T>
struct Stack <std::vector<T>*>
{
typedef typename std::vector<T>* ContainerPointerType;
static void push(lua_State* L, ContainerPointerType ptr)
{
ContainerPointerType* pp = (ContainerPointerType*)lua_newuserdata(L, sizeof(ContainerPointerType));
*pp = ptr;
}
static ContainerPointerType get(lua_State* L, int index)
{
return (ContainerPointerType)lua_touserdata(L, index);
}
};
Do not include <LuaBridge/Vector.h>, then solve this issue.

Generic vector class using unique_ptr follow up

I am trying to implement a generic vector class using std::unique_ptr. This is my first time doing this with smart pointers so I know I am probably making stupid errors. I just do not understand these errors:
1>------ Build started: Project: Vector, Configuration: Debug Win32 ------
1>main.cpp
1>c:\dev\vector\vector\vector.h(109): error C2676: binary '[': 'std::unique_ptr<T,std::default_delete<_Ty>>' does not define this operator or a conversion to a type acceptable to the predefined operator
1> with
1> [
1> T=int,
1> _Ty=int
1> ]
1>c:\dev\vector\vector\vector.h(105): note: while compiling class template member function 'Vector<int>::Vector(int,const T &)'
1> with
1> [
1> T=int
1> ]
1>c:\dev\vector\vector\main.cpp(19): note: see reference to function template instantiation 'Vector<int>::Vector(int,const T &)' being compiled
1> with
1> [
1> T=int
1> ]
1>c:\dev\vector\vector\main.cpp(14): note: see reference to class template instantiation 'Vector<int>' being compiled
1>c:\dev\vector\vector\vector.h(172): error C2676: binary '[': 'const std::unique_ptr<T,std::default_delete<_Ty>>' does not define this operator or a conversion to a type acceptable to the predefined operator
1> with
1> [
1> T=int,
1> _Ty=int
1> ]
1>c:\dev\vector\vector\vector.h(170): note: while compiling class template member function 'void Vector<int>::display(std::ostream &) const'
1>c:\dev\vector\vector\vector.h(80): note: see reference to function template instantiation 'void Vector<int>::display(std::ostream &) const' being compiled
1>c:\dev\vector\vector\vector.h(182): error C2676: binary '[': 'const std::unique_ptr<T,std::default_delete<_Ty>>' does not define this operator or a conversion to a type acceptable to the predefined operator
1> with
1> [
1> T=int,
1> _Ty=int
1> ]
1>c:\dev\vector\vector\vector.h(178): note: while compiling class template member function 'int Vector<int>::get(int) const'
1>c:\dev\vector\vector\main.cpp(23): note: see reference to function template instantiation 'int Vector<int>::get(int) const' being compiled
1>c:\dev\vector\vector\vector.h(190): error C2676: binary '[': 'std::unique_ptr<T,std::default_delete<_Ty>>' does not define this operator or a conversion to a type acceptable to the predefined operator
1> with
1> [
1> T=int,
1> _Ty=int
1> ]
1>c:\dev\vector\vector\vector.h(186): note: while compiling class template member function 'void Vector<int>::set(int,const T &)'
1> with
1> [
1> T=int
1> ]
1>c:\dev\vector\vector\main.cpp(22): note: see reference to function template instantiation 'void Vector<int>::set(int,const T &)' being compiled
1> with
1> [
1> T=int
1> ]
1>c:\dev\vector\vector\vector.h(225): error C2676: binary '[': 'std::unique_ptr<T,std::default_delete<_Ty>>' does not define this operator or a conversion to a type acceptable to the predefined operator
1> with
1> [
1> T=int,
1> _Ty=int
1> ]
1>c:\dev\vector\vector\vector.h(215): note: while compiling class template member function 'void Vector<int>::insert(int,T &&)'
1> with
1> [
1> T=int
1> ]
1>c:\dev\vector\vector\main.cpp(30): note: see reference to function template instantiation 'void Vector<int>::insert(int,T &&)' being compiled
1> with
1> [
1> T=int
1> ]
1>c:\dev\vector\vector\vector.h(225): error C2088: '[': illegal for class
1>c:\dev\vector\vector\vector.h(227): error C2676: binary '[': 'std::unique_ptr<T,std::default_delete<_Ty>>' does not define this operator or a conversion to a type acceptable to the predefined operator
1> with
1> [
1> T=int,
1> _Ty=int
1> ]
1>c:\dev\vector\vector\vector.h(238): error C2676: binary '[': 'std::unique_ptr<T,std::default_delete<_Ty>>' does not define this operator or a conversion to a type acceptable to the predefined operator
1> with
1> [
1> T=int,
1> _Ty=int
1> ]
1>c:\dev\vector\vector\vector.h(232): note: while compiling class template member function 'void Vector<int>::remove(int)'
1>c:\dev\vector\vector\main.cpp(28): note: see reference to function template instantiation 'void Vector<int>::remove(int)' being compiled
1>c:\dev\vector\vector\vector.h(238): error C2088: '[': illegal for class
1>Done building project "Vector.vcxproj" -- FAILED.
========== Build: 0 succeeded, 1 failed, 0 up-to-date, 0 skipped ==========
From what I gather I cannot use "[]" with unique ptr? Should I not use unique ptr then and use perhaps shared ptr?
Here is the header file:
#ifndef Vector_h
#define Vector_h
template <class T>
class Vector {
private:
static constexpr int initial_capacity = 100;
// Instance variables
int capacity = 0;
int size = 0;
std::unique_ptr<T> data = nullptr;
void deepCopy(const Vector<T> &source) {
capacity = source.size + initial_capacity;
for (int i = 0; i < source.size; i++) {
data[i] = source.data[i];
}
size = source.size;
}
void expandCapacity() {
auto oldData = std::move(data);
capacity *= 2;
for (int i = 0; i < size; i++) {
data[i] = oldData[i];
}
}
public:
// Constructors
Vector() = default; // empty constructor
Vector(int n, const T &value); // constructor
Vector(Vector<T> const &vec); // copy constructor
Vector<T>& operator=(Vector<T> const &rhs); // assignment operator
// Rule of 5
Vector(Vector<T> &&move) noexcept; // move constructor
Vector& operator=(Vector<T> &&move) noexcept; // move assignment operator
~Vector(); // destructor
// Overload operators
T& operator[](int index);
T const& operator[](int index) const;
bool operator==(const Vector<T>&) const;
//Vector<T>& operator+=(const Vector<T> &other) {
// Vector<T> newValue(size + other.size);
// std::copy(this->data, this->data + this->size, newValue.data);
// std::copy(other.data, other.data + other.size, newValue.data + this->size);
// newValue.swap(*this);
//}
friend Vector<T>& operator+(Vector<T> &source1, Vector<T> &source2) {
int n = source1.getSize() + source2.getSize();
static Vector<T> newSource(n,0);
for (int i = 0; i < source1.size; i++) {
newSource[i] = source1[i];
}
for (int i = 0; i < source2.size; i++) {
newSource[i + source1.getSize()] = source2[i];
}
return newSource;
}
friend std::ostream& operator<<(std::ostream &str, Vector<T> &data) {
data.display(str);
return str;
}
// Member functions
void swap(Vector<T> &other) noexcept;
void display(std::ostream &str) const;
int getSize() const { return size; }
int getCapacity() const { return capacity; }
bool empty() const { return size == 0; }
void clear() { size = 0; }
T get(int index) const;
void set(int index, const T &value);
void set(int index, T &&value);
void insert(int index, const T &value);
void insert(int index, T &&value);
void remove(int index);
void push_back(const T &value);
void pop_back();
};
template <class T>
Vector<T>::Vector(int n, const T &value) {
capacity = (n > initial_capacity) ? n : initial_capacity;
size = n;
for (int i = 0; i < n; i++) {
data[i] = value;
}
}
template <class T>
Vector<T>::Vector(Vector<T> const &vec) {
deepCopy(vec);
}
template <class T>
Vector<T>::Vector(Vector<T> &&move) noexcept {
move.swap(*this);
}
#endif /* Vector_h */
Here is the main.cpp file:
#include <algorithm>
#include <initializer_list>
#include <iostream>
#include <cassert>
#include <ostream>
#include "Vector.h"
int main() {
///////////////////////////////////////////////////////////////////////
///////////////////////////// VECTOR //////////////////////////////////
///////////////////////////////////////////////////////////////////////
Vector<int> nullVector; // Declare an empty Vector
assert(nullVector.getSize() == 0); // Make sure its size is 0
assert(nullVector.empty()); // Make sure the vector is empty
assert(nullVector.getCapacity() == 100); // Make sure its capacity is greater than 0
Vector<int> source(20, 0); // Declare a 20-element zero Vector
assert(source.getSize() == 20); // Make sure its size is 20
for (int i = 0; i < source.getSize(); i++) {
source.set(i, i);
assert(source.get(i) == i); // Make sure the i-th element has value i
}
return 0;
}
You understood the error message correctly when you assumed that
From what I gather I cannot use [] with unique ptr?
To be precise, you should not use [] with unique_ptr<T> when T is not an array type. You can use operator[] on unique_ptr<T[]>, though. The point of unique_ptr is the implied ownership tracking and automatic deletion when a unique_ptr owning an object is destructed. It does so with operator delete. This operator must not be used with arrays allocated using new T[count], just with single objects allocated with new T(constructor parameters). On the other hand, a special case of unique_ptr, spelled as unique_ptr<T[]>, uses delete[] on its object. So unsing unique_ptr<T[]> instead of unique_ptr<T> fixes both the problem of not having [] as well as unsing the wrong deletion function.

Forward declaration being ignored?

I have the below class (which is basically a wrapper for std::vector), and one of the functions returns a variable of the type AInteger (which is basically a wrapper for int). Now the type AInteger is used multiple times throughout the class, yet the compiler starts complaining at a very specific position. When I remove the "getSize()" function, everything compiles just fine.
There is mutual inclusion, so I need the forward declaration for everything to work.
One of the problems is that the AList class is a template, so it is impossible to move the definitions to a .cpp file (which would normally solve the problem).
What am I doing wrong?
Here's the class:
#ifndef ALIST_H
#define ALIST_H
#include <vector>
#include "AInteger.h"
class AInteger;
template<typename VALUE>
class AList {
public:
AList() {
}
AList(const std::vector<VALUE> list) {
value = list;
}
~AList() {
}
operator const std::vector<VALUE>() const {
return value;
}
std::vector<VALUE> toStdVector() const {
return value;
}
VALUE operator [](const AInteger index) const {
return value.at(index);
}
void add(const VALUE value) {
this->value.push_back(value);
}
VALUE get(const AInteger index) const {
return value[index];
}
AInteger getSize() const { // ERROR OCCURS HERE
return value.size();
}
void remove(const AInteger index) {
value.erase(index);
}
private:
std::vector<VALUE> value;
};
#endif
Output:
1>------ Build started: Project: ALibrary, Configuration: Debug Win32 ------
1> ASocket.cpp
1>d:\programs\programming\visual studio projects\c++\alibrary\alibrary\alist.h(43): error C2027: use of undefined type 'AInteger'
1> d:\programs\programming\visual studio projects\c++\alibrary\alibrary\alist.h(8): note: see declaration of 'AInteger'
1> d:\programs\programming\visual studio projects\c++\alibrary\alibrary\alist.h(53): note: see reference to class template instantiation 'AList<VALUE>' being compiled
1> AInteger.cpp
1>d:\programs\programming\visual studio projects\c++\alibrary\alibrary\alist.h(43): error C2027: use of undefined type 'AInteger'
1> d:\programs\programming\visual studio projects\c++\alibrary\alibrary\alist.h(8): note: see declaration of 'AInteger'
1> d:\programs\programming\visual studio projects\c++\alibrary\alibrary\alist.h(53): note: see reference to class template instantiation 'AList<VALUE>' being compiled
1> AHttpRequest.cpp
1>d:\programs\programming\visual studio projects\c++\alibrary\alibrary\alist.h(43): error C2027: use of undefined type 'AInteger'
1> d:\programs\programming\visual studio projects\c++\alibrary\alibrary\alist.h(8): note: see declaration of 'AInteger'
1> d:\programs\programming\visual studio projects\c++\alibrary\alibrary\alist.h(53): note: see reference to class template instantiation 'AList<VALUE>' being compiled
1> ABoolean.cpp
1>d:\programs\programming\visual studio projects\c++\alibrary\alibrary\alist.h(43): error C2027: use of undefined type 'AInteger'
1> d:\programs\programming\visual studio projects\c++\alibrary\alibrary\alist.h(8): note: see declaration of 'AInteger'
1> d:\programs\programming\visual studio projects\c++\alibrary\alibrary\alist.h(53): note: see reference to class template instantiation 'AList<VALUE>' being compiled
1> Generating Code...
1> Compiling...
1> AString.cpp
1> Generating Code...
2>------ Build started: Project: BitHoarder, Configuration: Debug Win32 ------
2> SystemHandler.cpp
2>d:\programs\programming\visual studio projects\c++\alibrary\alibrary\alist.h(43): error C2027: use of undefined type 'AInteger'
2> d:\programs\programming\visual studio projects\c++\alibrary\alibrary\alist.h(8): note: see declaration of 'AInteger'
2> d:\programs\programming\visual studio projects\c++\alibrary\alibrary\alist.h(53): note: see reference to class template instantiation 'AList<VALUE>' being compiled
2> Main.cpp
2>d:\programs\programming\visual studio projects\c++\alibrary\alibrary\alist.h(43): error C2027: use of undefined type 'AInteger'
2> d:\programs\programming\visual studio projects\c++\alibrary\alibrary\alist.h(8): note: see declaration of 'AInteger'
2> d:\programs\programming\visual studio projects\c++\alibrary\alibrary\alist.h(53): note: see reference to class template instantiation 'AList<VALUE>' being compiled
2> Generating Code...
========== Build: 0 succeeded, 2 failed, 0 up-to-date, 0 skipped ==========
If any more code is needed just ask and I will provide.
Thanks!
EDIT:
Here's the code that's inside "AInteger.h"
#ifndef AINTEGER_H
#define AINTEGER_H
#include "AList.h"
template<typename VALUE>
class AList;
class AInteger {
public:
AInteger();
AInteger(const int);
~AInteger();
operator const int() const;
int toInt() const;
AInteger operator=(const AInteger &);
AInteger & operator++();
AInteger & operator--();
AList<AInteger>splitByNumber(const AInteger &);
private:
int value;
};
#endif
To make matters even more confusing, the following class, which does THE EXACT SAME THING does not produce the error:
#ifndef ADICTIONARY_H
#define ADICTIONARY_H
#include <map>
#include "AInteger.h"
class AInteger;
template<typename KEY, typename VALUE, typename COMPARE = std::less<KEY>>
class ADictionary {
public:
ADictionary() {
}
ADictionary(const std::map<KEY, VALUE, COMPARE> dictionary) {
value = dictionary;
}
~ADictionary() {
}
operator const std::map<KEY, VALUE, COMPARE>() const {
return value;
}
std::map<KEY, VALUE, COMPARE> toStdMap() const {
return value;
}
VALUE operator [](const KEY key) const {
return value.at(key);
}
void add(const KEY key, const VALUE value) {
this->value.insert(std::make_pair(key, value));
}
VALUE get(const KEY key) const {
return value[key];
}
AInteger getSize() const { // No error here
return value.size();
}
void remove(const KEY key) {
value.erase(value.find(key));
}
private:
std::map<KEY, VALUE, COMPARE> value;
};
#endif
The implementation of getSize() must create an instance of AInteger. This is only possible if the full definition of AInteger is known. You cannot create an instance of a type which is only forward-declared.
And that's exactly what the compiler tells you: error C2027: use of undefined type 'AInteger'. It does not ignore the forward declaration but tells you that it's not enough.
As for the #include "AInteger.h", you do not show its contents, but possible problems are:
Buggy include guard in the header file causes the compiler to skip the definition.
The header file defines a different type with a similar name.
The definition of AInteger is within a namespace.
What's gone wrong is answered very well in Christian Hackl's answer and normally I'd drop it there, but I can't explain how the OP can fix this properly in a comment.
First a revised AInteger.h
#ifndef AINTEGER_H
#define AINTEGER_H
template<typename VALUE>
class AList;
class AInteger {
public:
AInteger();
AInteger(const int);
~AInteger();
//operator const int() const;
int toInt() const;
AInteger operator=(const AInteger &);
AInteger & operator++();
AInteger & operator--();
std::unique_ptr<AList<AInteger>> splitByNumber(const AInteger &);
void splitByNumber(const AInteger &,
AList<AInteger> &);
private:
int value;
};
#endif
The include of AList.h is gone. The forward declaration of AList remains I've provided two different splitByNumber methods. Pick one. The first creates and returns a pointer protected by a smart pointer. The second approach, and my personal preference, takes a reference to an AList created by the caller.
The thing is neither know anything about the inner workings of AList because all they care is about is A) It exists and b) they can get the address of one.
Bear with me while I explore both because I think they are both educational.
Alist.h remains unchanged except for the removal of the forward declaration of AInteger.
The two splitByNumber candidates sit in AInteger's implementation file which can safely include both AInteger.h and AList.h and thus has complete knowledge of both at the same time and can do all the magical things AIntegers and ALists can do.
std::unique_ptr<AList<AInteger>> AInteger::splitByNumber(const AInteger & integer)
{
std::unique_ptr<AList<AInteger>> listp(new AList<AInteger>());
// do stuff with listp
return listp;
}
void AInteger::splitByNumber(const AInteger & integer,
AList<AInteger> & list)
{
// do stuff with list
}
Using the pointer version:
std::unique_ptr<AList<AInteger>> alistp = aitest1.splitByNumber(aitest2);
alistp->add(somenumber);
Using the reference version:
AList<AInteger> alist; // first create an empty AList
aitest1.splitByNumber(aitest2, alist); // pass it into the function
alist.add(somenumber); // use the AList

Template container with multiple template parameters interacting with other template containers with a different template parameter

Wordy title, yes, but I was unsure how else to say it. Suppose I have a container class which has two template parameters, the first of which is a type, the second of which is the size of the local storage for the container.
Now we have multiple containers with a different container storage size. Essentially, the container functions (all the public ones, anyway) only really care about T; N is only used to allocate local storage (an allocator is used if N is not enough).
I have put together a simple example implementation that showcases the problem I am having.
#include <iostream>
template <typename T, size_t N = 10>
class TestArray
{
public:
T Local[N];
class Iterator
{
public:
T* Array;
int Index;
Iterator() : Array(NULL), Index(-1) { }
Iterator(T* _array, int _index) : Array(_array), Index(_index) { }
bool operator == (const Iterator& _other) const
{
return _other.Index == Index && _other.Array == Array;
}
void Next() { ++Index; }
void Prev() { --Index; }
T& Get() { return Array[Index]; }
};
T& operator [] (const int _index) { return Local[_index]; }
Iterator Begin() { return Iterator(Local, 0); }
Iterator End() { return Iterator(Local, N); }
template <size_t _N>
void Copy(const TestArray<T, _N> &_other, int _index, int _count)
{
int i;
for (i = 0; i < _count; i++)
Local[_index + i] = _other[i];
}
};
This is really a two part question. I will concern this question only with the first part, and ask another regarding the second. I tried using it as follows:
int main() {
TestArray<int> testArray1;
TestArray<int, 25> testArray2;
TestArray<int>::Iterator itr1;
TestArray<int, 25>::Iterator itr2;
itr1 = testArray1.Begin();
for (itr1 = testArray1.Begin(); itr1 != testArray1.End(); itr1.Next())
{
itr1.Get() = itr1.Index;
}
testArray2.Copy(testArray1, 0, 10);
for (itr2 = testArray2.Begin(); itr2 != testArray2.End(); itr2.Next())
{
std::cout << itr2.Get() << std::endl;
}
return 0;
}
Here is an IDEONE link: http://ideone.com/1XKwD
When compiled with gcc-4.3.4, I get the following.
prog.cpp: In member function ‘void TestArray<T, N>::Copy(const TestArray<T, _N>&, int, int) [with unsigned int _N = 10u, T = int, unsigned int N = 25u]’:
prog.cpp:82: instantiated from here
prog.cpp:63: error: passing ‘const TestArray<int, 10u>’ as ‘this’ argument of ‘T& TestArray<T, N>::operator[](int) [with T = int, unsigned int N = 10u]’ discards qualifiers
When compiled with VS2010, I get the following.
1>------ Build started: Project: testunholytemplatemess, Configuration: Debug Win32 ------
1> main.cpp
1>c:\users\james\documents\testproj\testunholytemplatemess\testunholytemplatemess\main.cpp(63): error C2678: binary '[' : no operator found which takes a left-hand operand of type 'const TestArray<T>' (or there is no acceptable conversion)
1> with
1> [
1> T=int
1> ]
1> c:\users\james\documents\testproj\testunholytemplatemess\testunholytemplatemess\main.cpp(44): could be 'int &TestArray<T>::operator [](const int)'
1> with
1> [
1> T=int
1> ]
1> while trying to match the argument list '(const TestArray<T>, int)'
1> with
1> [
1> T=int
1> ]
1> c:\users\james\documents\testproj\testunholytemplatemess\testunholytemplatemess\main.cpp(82) : see reference to function template instantiation 'void TestArray<T,N>::Copy<10>(const TestArray<T> &,int,int)' being compiled
1> with
1> [
1> T=int,
1> N=25
1> ]
Maybe I'm being thick, but I'm failing to interpret what either of these is actually trying to tell me (still somewhat new to templates). I also fail to understand why the operator [] method should really care about N, or the fact that I'm calling operator [] on a container with a different N value. If you change _other[i] to _other.Local[i], it works fine.
Does anyone have any suggestions?
You have to overload two versions for the []-operator, a const one and a non-const one:
T & operator [] (size_t _index) { return Local[_index]; }
const T & operator [] (size_t _index) const { return Local[_index]; }
Your constant Copy function is only allowed to use the second, constant version!