I have a template vector class. This is how a part of it looks like:
template<class Type>
class Vector
{
public:
Vector(int size)
{
MyTime = new Type[size];
m_size = size;
m_current = -1;
}
void set(int i,Type &data)
{
data[i]=Mytime[i];
}
private:
Type* MyTime;
int m_size;
int m_current;
};
Then i wish to use the set method above to set the value into a string "records".
for(int i=0 ; i<count ; i++)
{
records.set(i)=dateList.get(i)+timeList3.get(i);
}
But it gives me two errors:
1. too few argument in function call.
2. expression must be a modifiable lvalue.
Both errors appear at the records.set(i).
The declaration of "records" is:
Vector<string> records(100);
This makes me quite confuse. May I know how to solve it?
I think that records.set(i)=dateList.get(i)+timeList3.get(i); is supposed to be this:
records.set(i, dateList.get(i) + timeList3.get(i));
too few argument in function call. - In your example you only pass i, meanwhile there are two arguments required to set
expression must be a modifiable lvalue - set() return void, it's not a method that returns a modifiable lvalue.
Meanwhile, you vector class does some weird things. This is a basic template vector class.
template <typename T>
class Vector
{
public:
Vector(int size) : data(new T[size]) {}
void Set(int index, const T& val) { data[index] = val; }
T Get(int index) { return data[index]; }
private:
T* data;
}
Related
I have the following scenario:
class ScalarField
{
void* _buffer; //Array for data.
};
And a derived class:
template <typename T>
class ScalarFieldT : public ScalarField
{
ScalarFieldT(int size)
{
_data = new T[size];
_buffer = _data;
}
T& get(int index)
{
return _data[index];
}
T* _data; // Typed array for data
};
Notice that T can assume only basic types such float, int, double and so on.
This is a very old legacy code, so I don't have too much flexibility to adjust it properly doing a better design. What a need to do is to access the data from ScalarField::_buffer with the correct typecasting of it derived class.
Something like this:
void main()
{
int n = TOTAL_SIZE;
ScalarFieldT<int> typedScalarField(n);
ScalarField* scalarField = &typedScalarField;
// This is what I need to do:
int index = ELEMENT_INDEX;
float value = scalarField->method(index); // Get the value from base class correctly converted from int to float, for example.
}
The point is, I only have access to the base class abstraction, but I need to get the value from _buffer converted to another simple data type, such float, int, uchar, etc.
What do you guys recommend?
Thanks in advance!
You can use a type that provides a set of cast operators as a return type for method.
It follows a minimal, working example:
#include<memory>
class ScalarField {
protected:
struct Value {
virtual operator float() const = 0;
virtual operator int() const = 0;
// ...
};
public:
virtual const Value & method(int i) = 0;
protected:
void* buffer;
};
template <typename T>
class ScalarFieldT : public ScalarField {
struct TValue: Value {
TValue(T value): value{value} {}
operator float() const override { return float(value); }
operator int() const override { return int(value); }
// ...
private:
T value;
};
public:
ScalarFieldT(int size) {
data = new T[size];
buffer = data;
}
T& get(int index) {
return data[index];
}
const Value & method(int i) {
std::make_unique<TValue>(data[i]);
}
private:
std::unique_ptr<Value> value;
T* data;
};
int main() {
ScalarFieldT<int> typedScalarField(10);
ScalarField* scalarField = &typedScalarField;
float f = scalarField->method(2);
int i = scalarField->method(5);
}
Hm - please don't throw stones on me for a probably silly answer, but...
Let's assume that T is restricted to numeric data types, e.g. int, long, double, float, and let's further assume that the largest integral value to be stored is about 2^53. Then double could serve as an data exchange data type, to which any other data type can be converted without losing precision.
Then one could define virtual double ScalarField::method(int index) = 0, which is then overloaded accordingly in the typed variants, which do an "up"-cast from actual type T to double.
Unless you are allowed to encapsulate the values in an object (e.g. struture/class Value), the following code using the "use double as data exchange data type" could work:
class ScalarField
{
public:
void* _buffer; //Array for data.
virtual double method(int index) = 0;
};
template <typename T>
class ScalarFieldT : public ScalarField
{
public:
ScalarFieldT(int size)
{
_data = new T[size];
_buffer = _data;
}
virtual double method(int index) { return get(index); }
T& get(int index)
{
return _data[index];
}
T* _data; // Typed array for data
};
hello i want to create simple array class to get value and insert value like (array[0] = 4) and this is my program but i have problem to use [] = in same time for insert
template <typename Param>
class arr
{
private:
int Last_point = 0;
Param Data[];
public:
void& operator[]=(int Element_id, Param v)
{
Data[Element_id] = v;
}
Param& operator[] (int Element_id)
{
return Data[Element_id];
}
};
void main()
{
arr <int> Array;
Array[1] = 555;
cout << "Is(" << to_string(Array[1]) << ")" << endl;
system("pause");
}
is there any operator like ([]=)? or for this, i have to use which methods? also i want to get value if just used []
The syntax you are attempting for the operator[] functions is quite wrong. You need something like:
// Version for non-const objects
Param& operator[](std::size_t i)
{
return Data[i];
}
// Version for const objects
Param const& operator[](std::size_t i) const
{
return Data[i];
}
If you want to support arrays whose sizes are known at compile time, you can use:
template <typename Param, std::size_t N>
class arr
{
private:
Param Data[N];
public:
Param& operator[](std::size_t i)
{
return Data[i];
}
Param const& operator[](std::size_t i) const
{
return Data[i];
}
};
If you want to support arrays whose sizes are known at run time, you can use the following. However, you need to be aware of The Rule of Three and make sure to implement the copy constructor and the copy assignment operator properly.
template <typename Param>
class arr
{
private:
Param* Data;
public:
arr(size_t size) : Data(new Param[size]) {}
~arr() { delete [] Data; }
Param& operator[](std::size_t i)
{
return Data[i];
}
Param const& operator[](std::size_t i) const
{
return Data[i];
}
};
Foo& operator[] is sufficient for reading and writing.
Include the size of the array as a template parameter, or replace Param[] with std::vector<Param>.
Use size_t instead of int for array index types.
You don't need to wrap Array[1] in to_string for output.
Don't use void main! The standard says main must be int.
void& is not valid C++ either.
#include <iostream>
using namespace std;
template <typename Param, size_t Size> class arr {
private:
Param Data[Size];
public:
Param &operator[](size_t Element_id) {
return Data[Element_id];
}
};
int main() {
arr<int, 3> Array;
Array[1] = 555;
cout << "Is(" << Array[1] << ")" << endl;
}
However, all that arr does in my snippet is be a less useful std::array!
I've been getting this error for some time, and I have no clue how to fix it.
I searched for similar problem here on stack overflow, but I've failed to find anything.
Source code:
template <typename T>
class Dynamic_Array
{
private:
T* actual_array;
unsigned int number_of_elements;
public:
Dynamic_Array() {}
~Dynamic_Array() {delete[] actual_array;}
unsigned int get_size() const {return number_of_elements;}
T& operator [](unsigned int index) {return actual_array[index];}
void operator +=(T&);
void operator -=(unsigned int);
};
template <typename T> /*Not sure if this is needed, but compiler doesn't mind, still prints the same error*/
void Dynamic_Array<T>::operator+=(T& object)
{
if(number_of_elements>1)
{
T* temp_array = new T[number_of_elements];
for(unsigned int i=0;i<number_of_elements;i++)
{
temp_array[i]=actual_array[i];
}
delete[] actual_array;
actual_array = new T[number_of_elements+1];
for(unsigned int i=0;i<number_of_elements;i++)
{
actual_array[i]=temp_array[i];
}
delete [] temp_array;
temp_array=NULL;
actual_array[number_of_elements]=object;
number_of_elements++;
}
else
{
number_of_elements++;
actual_array = new T[1];
}
}
void Dynamic_Array<T>::operator-=(unsigned int index)
{
T* temp_array = new T[number_of_elements-1];
for(unsigned int i=0, j=0;i<number_of_elements;i++)
{
if(i!=index)
{
temp_array[j]=actual_array[i];
j++;
}
}
delete[] actual_array;
number_of_elements--;
actual_array = new T[number_of_elements];
for(unsigned int i=0;i<number_of_elements;i++)
{
actual_array[i]=temp_array[i];
}
delete [] temp_array;
temp_array = NULL;
}
According to compiler, the error is present in line 18 (the empty one between "};" and "template"
As I said, I have no idea what I screwed up, so any help is appreciated.
When you define member functions outside of a class template declaration then you need to specify the template for each function. When you define
void Dynamic_Array<T>::operator-=(unsigned int index)
{
//...
}
You need to have the template part as well like
template <typename T>
void Dynamic_Array<T>::operator-=(unsigned int index)
{
//...
}
This has to be present for every function definition that you do out of line. A single template <typename T> at the start of all the definition does not apply to all of the function definitions.
Dynamic_Array is a template class so when defining operator+= and operator-= outside the scope of the class you need to provide template type as follows:
template<typename T> void Dynamic_Array<T>::operator+=(T& object) {
//...
}
template<typename T> void Dynamic_Array<T>::operator-=(unsigned int index) {
//...
}
Also, I should note that it is somewhat odd to have void as a return type for operator+= and operator-=, typically you should return a reference to the altered instance of this, i.e:
template<typename T> Dynamic_Array<T>& Dynamic_Array<T>::operator+=(const T& object) {
//...
}
I'm trying to learn about templates and template specialisation. I'm writing a template class for arrays, using template specialisation to avoid code bloat. Thus I have a fully specialised template MyArray and then I inherit from this one like class MyArray<T*> : private MyArray<void*>. I'm having trouble overloading the subscript operators (one for non-const refs, one for const refs). Here's a piece of code (far from complete, but contains my problem).
#include <iostream>
using std::cout;
using std::cin;
using std::endl;
/*** template class MyArray **/
template <class T>
class MyArray {};
/*** Full template specialization for MyArray holding pointers ***/
template <>
class MyArray<void*> {
public:
explicit MyArray(unsigned s = 100) : sz(s) {
data = new void*[s];
}
virtual ~MyArray() { delete[] data; }
/** subscript operator overload for non-const refs **/
void*& operator[](unsigned i) {
return data[i];
}
/** subscript operator overload for const refs **/
const void*& operator[](unsigned i) const {
return data[i]; // line 26
}
unsigned size() const { return sz; }
private:
void** data;
unsigned sz;
};
/** Partial specialization: create the template class by inheriting from the one above **/
template <class T>
class MyArray<T*> : private MyArray<void*> {
public:
explicit MyArray(unsigned s = 100) : MyArray<void*>::MyArray(s) {
data = new T*[s];
}
virtual ~MyArray() { delete[] data; }
/** subscript operator overload for non-const refs **/
T*& operator[](unsigned i) {
return reinterpret_cast<T*&>( // line 47
MyArray<void*>::operator[](i)
);
}
/** subscript operator overload for const refs **/
const T*& operator[](unsigned i) const {
return reinterpret_cast<const T*&>(
MyArray<void*>::operator[](i)
);
}
unsigned size() const { return MyArray<void*>::size(); }
private:
T** data;
};
/** input function for filling MyArray's **/
template <class T>
void InputMyArray(MyArray<T*>& my_array) {
unsigned size = 0;
T tmp;
while (cin >> tmp) {
T* i = new T;
*i = tmp;
my_array[size++] = i;
}
}
/** output function for printing elements of MyArray's **/
template <class T>
void OutputArray(const MyArray<T*>& my_array) {
for (unsigned i = 0; i < my_array.size(); i++) {
cout << *my_array[i] << " ";
}
cout << endl;
}
int main() {
/** Initialize array, fill it, print contents **/
MyArray<int*> p;
InputMyArray(p);
cout << "MyArray of pointer to ints holds int values: " << endl;
OutputArray(p);
return 0;
}
The compiler (clang) is complaining (error) about line 26
non-const lvalue reference to type 'const void *' cannot bind to a value of unrelated type 'void *'
I suppose I don't want the compiler to interpret this as a non-const reference - what I want is for it to be const. How can I properly overload this operator in this context? The corresponding piece of code works fine for a template class without specialisation, like MyArray<T>.
The compiler further complains (warnings) about the reinterpret_casts which apparently contain undefined behaviour
reinterpret_cast from 'void *' to 'int *&' has undefined behavior
(line 47). The reinterpret_casts are essentially copy-pasted from my instructions, so I would think they are to be used like this. I don't know why the reference to void* isn't picked up. What am I doing wrong here?
Your template is a container for void*, not const void*:
/** subscript operator overload for const refs **/
void* const& operator[](unsigned i) const {
return data[i]; // line 26
}
Same for T*:
/** subscript operator overload for const refs **/
T* const& operator[](unsigned i) const {
return reinterpret_cast<T*const&>(
MyArray<void*>::operator[](i)
);
}
There are some Classes: Array, NumericArray. Array is a template class, and NumericArray is a class inherited from Array designed to take int, double, etc.
Part of Header of NumericArray:
template <class T = int>
class NumericArray : public Array<T>{
private:
T* m_data;
int size;
public:
NumericArray<T> operator * (T factor)const;
};
here are constructors and some functions of NumericArray:
template <class T>
NumericArray<T>::NumericArray(){
m_data = new T[10];
size = 10;
}
template <class T>
NumericArray<T>::NumericArray(int n){
m_data = new T[n];
size = n;
}
template <class T>
NumericArray<T>::NumericArray(const NumericArray<T>& s_data){
m_data = new T[s_data.size];
// assign elements in the source array
for (int i = 0;i<=(s_data.Size()-1 ); i++){
m_data[i] = s_data.m_data[i];
}
size = s_data.Size();
}
/* Destructor */
template <class T>
NumericArray<T>::~NumericArray(){
delete [] m_data;
}
template <class T>
NumericArray<T> NumericArray<T>::operator * (T factor)const{
NumericArray<T> temp(size);
for (int i = 0; i<size;i++){
temp.m_data[i] = (*this)[i] *factor;
}
return temp;
}
And when I call it in the main(), something weird happens. For example:
NumericArray<int> intArray1(10);
NumericArray<int> intArray2;
for(int i =0; i<10;i++){
intArray1[i] = i;
intArray2[i] = i;
}
The 2 arrays do contain numbers 0-9, but if I call
NumericArray intArray4 = intArray1*2;
intArray4 consists of zero(0)s. It seems that the default constructor is called in the function and passed to Array4. And after the operator, Array1 and Array2 are still numbers 0-9
Below are the related code of Array
template class Array{
private:
T* m_data;
int size;
public:
Array(); // constructor
Array(int n); // constructor
Array(const Array<T>& s_data); //Copy Constructor
virtual ~Array(); // destructor
void SetElement(int i, const T& source);
T& GetElement(int i)const;
int Size() const;
int DefaultSize()const;
void DefaultSize(int n);
// Operator overloading
Array<T>& operator = (const Array<T>& source) ;
T& operator [](int i);
const T& operator [] (int i) const;
};
template <class T>
Array<T>::Array(){
// default constructor
m_data = new T[defaultSize]; // initialize T*
size = defaultSize; // initialize integer
}
template <class T>
Array<T>::Array(int n){
// Constructor with arguments
m_data = new T[n];
size = n;
}
template <class T>
Array<T>::Array(const Array<T>& s_data){
// Copy constructor
m_data = new T[s_data.Size()];
// assign elements in the source array
for (int i = 0;i<=(s_data.Size()-1 ); i++){
m_data[i] = T( s_data.m_data[i]);
}
size = s_data.Size();
defaultSize = s_data.Size();
}
template <class T>
T& Array<T>::operator [](int i) {
if (i > size|| i<0){
OutOfBoundsException a;
throw a;
}
return m_data[i];
}
Not sure if provided enough information. Any hint is greatly appreciated.
The easiest way to access base class data members when the base is a (dependent) class template, is a using declaration like this:
#include <iostream>
using namespace std;
template< class Item >
class Base
{
protected:
Item item_;
Base( Item const& v ): item_( v ) {}
};
template< class Item >
class Derived
: public Base< Item >
{
protected:
using Base<Item>::item_;
public:
auto value() const -> Item { return item_; }
Derived( Item const& v ): Base<Item>( v ) {}
};
auto main() -> int
{
Derived<int> const x( 42 );
cout << x.value() << endl;
}
Alternatively you can qualify the access, e.g. this->item_ or Base<Item>::item_.
That said, it’s usually not a good idea to let derived classes access base class data members directly.
Here is the problem: both NumericArray and Array have
T* m_data;
int size;
The function Array::operator[] is called from Array which uses Array::m_data, however the NumericArray::operator* sets NumericAray::m_data. It probably is working as you would expect, but you are reading from the wrong pointer.
Remove the members from NumericArray and make the members protected instead of private in Array. The second part is optional if the implementation is changed a little bit.