Why is VS giving me this error? I am quite new to OOP and Templates in C++ and I am trying to write simple Stack implementation using these techniques. I tried to google it but I did not find anything useful.
Code:
#ifndef _STACK
#define _STACK
template <class T>
class Stack {
public:
Stack();
Stack(const int &num);
Stack(const Stack<T> &obj);
Stack& operator=(const Stack<T> &obj);
~Stack();
private:
T * buffer;
unsigned int actualSize;
unsigned int maxSize;
};
template <class T>
Stack<T>::Stack() : maxSize(5), actualSize(0), buffer(new T[5]) {};
template <class T>
Stack<T>::Stack(const int &num) : maxSize(num), actualSize(num), buffer(new T[num]) {};
template <class T>
Stack<T>::Stack(const Stack<T> &obj) {
this->actualSize = obj.actualSize;
this->maxSize = obj.maxSize;
std::copy(obj.buffer, obj.buffer + obj.actualSize, this->buffer);
}
template <class T>
Stack<T>& Stack<T>::operator=(const Stack<T> &obj) {
T * temp = new T[obj.actualSize];
std::copy(obj.buffer, obj.buffer + obj.actualSize, temp);
this->actualSize = obj.actualSize;
this->maxSize = obj.maxSize;
delete[] buffer;
buffer = temp;
return *this;
}
template <class T>
Stack<T>::~Stack() {
delete[] buffer;
}
#endif
Full build log - obviously there is a problem with std::copy :
1>------ Build started: Project: Stack, Configuration: Debug Win32 ------
1>main.cpp
1>c:\program files (x86)\microsoft visual studio\2017\community\vc\tools\msvc\14.14.26428\include\xutility(2483): warning C4996: 'std::copy::_Unchecked_iterators::_Deprecate': Call to 'std::copy' with parameters that may be unsafe - this call relies on the caller to check that the passed values are correct. To disable this warning, use -D_SCL_SECURE_NO_WARNINGS. See documentation on how to use Visual C++ 'Checked Iterators'
1>c:\program files (x86)\microsoft visual studio\2017\community\vc\tools\msvc\14.14.26428\include\xutility(2483): note: see declaration of 'std::copy::_Unchecked_iterators::_Deprecate'
1>c:\users\peter\documents\pb071hw\circle\stack\stack.h(34): note: see reference to function template instantiation '_OutIt std::copy<T*,T*>(_InIt,_InIt,_OutIt)' being compiled
1> with
1> [
1> _OutIt=int *,
1> T=int,
1> _InIt=int *
1> ]
1>c:\users\peter\documents\pb071hw\circle\stack\stack.h(32): note: while compiling class template member function 'Stack<int> &Stack<int>::operator =(const Stack<int> &)'
1>c:\users\peter\documents\pb071hw\circle\stack\main.cpp(13): note: see reference to function template instantiation 'Stack<int> &Stack<int>::operator =(const Stack<int> &)' being compiled
1>c:\users\peter\documents\pb071hw\circle\stack\main.cpp(10): note: see reference to class template instantiation 'Stack<int>' being compiled
1>Stack.vcxproj ->
Related
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.
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.
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
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.
I've been butting my head against this problem in an assignment I've been working on, and can't seem to get it to work at all. I wrote a little test class to demonstrate what I'm trying to do, and hopefully someone can explain what I need to do.
//Tester class
#include <iostream>
using namespace std;
template <typename T>
class Tester
{
typedef void (Tester<T>::*FcnPtr)(T);
private:
T data;
void displayThrice(T);
void doFcn( FcnPtr fcn );
public:
Tester( T item = 3 );
void function();
};
template <typename T>
inline Tester<T>::Tester( T item )
: data(item)
{}
template <typename T>
inline void Tester<T>::doFcn( FcnPtr fcn )
{
//fcn should be a pointer to displayThrice, which is then called with the class data
fcn( this->data );
}
template <typename T>
inline void Tester<T>::function()
{
//call doFcn with a function pointer to displayThrice()
this->doFcn( &Tester<T>::displayThrice );
}
template <typename T>
inline void Tester<T>::displayThrice(T item)
{
cout << item << endl;
cout << item << endl;
cout << item << endl;
}
-and here's main:
#include <iostream>
#include "Tester.h"
using namespace std;
int main()
{
Tester<int> test;
test.function();
cin.get();
return 0;
}
-and lastly, my compiler errors (VS2010)
c:\users\name\documents\visual studio 2010\projects\example\example\tester.h(28): error C2064: term does not evaluate to a function taking 1 arguments
1> c:\users\name\documents\visual studio 2010\projects\example\example\tester.h(26) : while compiling class template member function 'void Tester<T>::doFcn(void (__thiscall Tester<T>::* )(T))'
1> with
1> [
1> T=int
1> ]
1> c:\users\name\documents\visual studio 2010\projects\example\example\tester.h(21) : while compiling class template member function 'Tester<T>::Tester(T)'
1> with
1> [
1> T=int
1> ]
1> c:\users\name\documents\visual studio 2010\projects\example\example\example.cpp(7) : see reference to class template instantiation 'Tester<T>' being compiled
1> with
1> [
1> T=int
1> ]
Hopefully, my comments in the Tester class will tell you what I'm trying to do. Thank you for taking the time to look at this!
You're not calling the member function pointer corrently; it requires the use of a special operator called the pointer-to-member operator.
template <typename T>
inline void Tester<T>::doFcn( FcnPtr fcn )
{
(this->*fcn)( this->data );
// ^^^
}
To call a member function via a pointer-to-member-function plus instance pointer, you need the ->* syntax, minding operator precedence:
(this->*fcn)(data);
You need to explicitly add the object you message:
(*this.*fcn)(this->data); // << '*this' in this case
see also the C++ FAQ