I've seen other questions on here, but they deal with pointers, or with qobject derived classes, so they didn't seem relevant.
I am trying to append values into a qlist of custom classes, here is the class
class matchPair
{
public:
matchPair(int a=0, int b=0)
: m_a(a)
, m_b(b)
{}
int a() const { return m_a; }
int b() const { return m_b; }
bool operator<(const matchPair &rhs) const { return m_a < rhs.a(); }
// matchPair& operator=(const matchPair& other) const;
private:
int m_a;
int m_b;
};
class videodup
{
public:
videodup(QString vid = "", int m_a = 0, int m_b = 0);
~videodup() {}
QString video;
bool operator==(const QString &str) const { return video == str; }
// videodup& operator=(QString vid, int m_a, int m_b);
QList<matchPair> matches;
};
struct frm
{
QString file;
int position;
cv::Mat descriptors;
QList<videodup> videomatches;
};
QList<frm> frames;
and the line that fails is:
frame.videomatches.at( frame.videomatches.indexOf(vid) ).matches.append(pair);
the error I get is:
/usr/local/Cellar/qt5/5.5.1_2/lib/QtCore.framework/Headers/qlist.h:191: candidate function not viable: 'this' argument has type 'const QList<matchPair>', but method is not marked const
void append(const T &t);
^
what am I doing wrong?
You are trying to append a value to a const QList<T>, which means your QList<T> is constant, i.e. non-mutable. Look closely, the error reads this has type const QList<matchPair>, and you can only call const methods on a const object, while append() obviously is not const both syntactically and semantically. Fix the QList<matchPair> to not be const.
Edit 2:
Having looked closer at the code, here is the culprit, indeed:
frame.videomatches.at( frame.videomatches.indexOf(vid) ).matches.append(pair);
^^
QList<T>::at() returns const T&, which leads to the problem I've described above. Use QList<T>::operator[]() insdead,which has overloads that return both a const T and T values.
Edit:
However, which compiler brand and version is this? I can't reproduce this error message in g++ by calling a non-const method on a const class object, both templated and non-templated (I am getting an error, but it's worded differently).
Related
The code below is a simplified version of the actual problem I am facing.
Assume I do not have permission to modify class A (as it is external library), and its already widely used in my existing code base.
The const & assignment from a temporary object (direct constructor) which also return a const & member variable via implicit conversion is not valid in this case.
How do I prevent or make it legal in this case so that the caller gets the correct A value?
class A
{
public:
A() { }
A(int _r, int _g, int _b)
: r(_r), g(_g), b(_b)
{
}
~A(){ }
int GetR() const { return r; }
int GetG() const { return g; }
int GetB() const { return b; }
private:
int r = 0;
int g = 0;
int b = 0;
};
class Foo
{
public:
Foo() : Foo(A()) {}
Foo(int _r, int _g, int _b) : a(A(_r, _g, _b)) {}
explicit Foo(const A& _a) : a(_a) {}
Foo& operator=(const A& a)
{
*this = Foo(a);
return *this;
}
operator A() const { return a; }
operator const A&() const { return a; }
private:
A a;
};
int main()
{
const A& a = Foo(200, 100, 300);
std::cout << a.GetR() << a.GetG() << a.GetB() << endl; // I may not get 200 100 300 here as Foo is already out of scope
return 0;
}
Motivation
Some background on why I am implementing a class as above. The actual purpose of class Foo is to contain 2 different objects, which actually has the same purpose, just different way of storing data internally. For example, let's say class A and class B, which stores RGB value of color in int and floating (normalized) respectively. And as mentioned above, I do not have permission to modify class A, and its already widely used in my code base.
There are tons of function in my code base which takes in const A& and const B& as a function param. So I am trying to unify this 2 classes for a particular case, where I can just pass in Foo in those places and it will work as expected.
You can apply ref-qualified member functions (since C++11), i.e. mark the conversion operator with lvalue-reference, to prevent it being called on temporaries (rvalues).
class Foo
{
public:
... ...
operator A() const { return a; }
operator const A&() const & { return a; }
operator const A&() && = delete;
... ...
};
Then
const A& a = Foo(200, 100, 300); // invalid; invokes deleted operator
const A& a = static_cast<A>(Foo(200, 100, 300)); // fine; invokes operator A()
In C++ I'm often facing a situation when I need to prepare const and non-const version of class in analogy to const_iterator and iterator from standard library.
class const_MyClass
{
public:
const_MyClass(const int * arr):
m_arr(arr)
{
}
int method() const; //does something with m_arr without modifying it
private:
const int * m_arr;
}
class MyClass
{
public:
MyClass(int * arr):
m_arr(arr)
{
}
int method() const; //does something with m_arr without modifying it
void modify(int i); //modify m_arr
private:
int * m_arr;
}
The problem with this is that I need to repeat whole code of const_MyClass in MyClass and distribute any changes in API to both classes. Thus sometimes I inherit const_MyClass and do some const_casts, which also isn't perfect and pretty solution. Still when I want to pass const_MyClass instance by reference it looks moronic:
void func(const const_MyClass & param)
Instance param is marked with two "consts", and it has only const methods...
This is where const constructors would be handy, but are there any existing alternatives?
Some use examples to explain problem better:
//ok to modify data
void f(int * data)
{
MyClass my(data);
my.modify();
...
}
//cant modify data, cant use MyClass
void fc(const int * data)
{
const_MyClass my(data);
int i = my.method();
...
}
You can make a template class to act as a base, like this:
template<typename T>
class basic_MyClass
{
public:
basic_MyClass(T * arr) :m_arr(arr) {}
int method() const; //does something with m_arr without modifying it
private:
T * m_arr;
};
Then, for your const version, since it doesn't add anything, you can just use a typedef:
typedef basic_MyClass<const int> const_MyClass;
For your non-const version, you can inherit:
class MyClass : public basic_MyClass<int>
{
public:
using basic_MyClass::basic_MyClass; // inherit all the constructors
void modify(int i); //modify m_arr
};
Have you considered simply tracking two pointers and raising exceptions from the mutable operations when no mutable value is available? Maybe an example will help describe what I am thinking of.
class MyClass
{
public:
MyClass(int *mutable_data):
m_mutable_view(mutable_data), m_readonly_view(mutable_data)
{
}
MyClass(const int *immutable_data):
m_mutable_view(NULL), m_readonly_view(immutable_data)
{
}
int retrieve_value(int index) {
return m_readonly_view[index];
}
void set_value(int index, int value) {
require_mutable();
m_mutable_view[index] = value;
}
protected:
void require_mutable() {
throw std::runtime_error("immutable view not available");
}
private:
const int *m_readonly_view;
int *m_mutable_view;
};
The idea is pretty simple here - use a sentinel value to indicate whether modifications are possible or not instead of depending on the type system to do that for you. Personally, I would think about doing the inheritance based approach that #BenjaminLindley suggested but I wanted to present a slightly different solution that might not have occurred to you.
After talk with Neil Kirk I realized what I was doing wrong. I started by separating data from logic as he suggested.
This attempt resulted in two classes MyClassPtr and const_MyClassPtr. They only provide functions for data access (like iterators) and may look like that:
class const_MyClassPtr
{
public:
const_MyClassPtr(const int * arr);
int operator [](int i) const;
const int * ptr() const;
private:
const int * m_arr;
}
class MyClassPtr
{
public:
MyClassPtr(int * arr);
int operator [](int i) const;
int & operator [](int i);
const int * ptr() const;
int * ptr();
//promotion to const pointer
const_MyClassPtr () const {return const_MyClassPtr(m_arr);}
private:
int * m_arr;
}
Now it is clear that objects of these classes should be treated like pointers, so when I use them as function parameters I pass them by value!
void func(const_MyClassPtr param) //instead of void func(const const_MyClass & param)
To provide methods I have created MyClassOp class template and used static polymorphism.
template <class DERIVED>
class MyClassOp
{
public:
const DERIVED & derived() const {return static_cast<const DERIVED &>(*this)}
DERIVED & derived() {return static_cast<DERIVED &>(*this)}
int method() const; //operates on derived() const
void modify(int i); //operates on derived()
}
MyClassOp is a collection of methods. It does not have state. In general it is a trait. To make these methods accessible I overloaded -> and * operators
class const_MyClassPtr : private MyClassOp<const_MyClassPtr>
{
public:
const MyClassOp<MyClassPtr> * operator ->() const {return this;}
const MyClassOp<MyClassPtr> & operator *() const {return *this;}
...
}
class MyClassPtr : private MyClassOp<MyClassPtr>
{
public:
MyClassOp<MyClassPtr> * operator ->() {return this;}
MyClassOp<MyClassPtr> & operator *() {return *this;}
...
}
This works O.K., but is a bit cumbersome. If I have for example equality operator I need to write something like *myptr1 == myptr2 to compare values kept by two MyClassPtr objects (it's easy to make a mistake and compare myptr1 == myptr2 or expect that something like *myptr1 == *myptr2 could work). Also when I have allocating type:
class MyClass : public MyClassOp<MyClass>
{
MyClass(int x, int y, int z);
...
int m_arr[3];
}
I would want to be able to use temporaries as function arguments.
void f(const_MyClassPtr my);
//use temporary when calling f()
f(MyClass(1, 2, 3));
I can do this by providing conversion operators or conversion constructors (that convert MyClass to const_MyClassPtr). But then const_MyClassPtr behaves more like reference than pointer. If iterators are generalization of pointers then why one could not imitate reference? Therefore I divided MyClassOp into two parts (const and non const) and replaced -> and * operators implemented by const_MyClassPtr and MyClassPtr with public inheritance and changed their names to ressemble reference. I ended up with following structures.
MyClassOp : public const_MyClassOp
const_MyClassRef : public const_MyClassOp<const_MyClassRef>
MyClassRef : public MyClassOp<MyClassRef>
MyClass : public MyClassOp<MyClass>
However const_MyClassRef and MyClassRef are not perfect generalization of reference as it impossible to imitate some of C++ reference properties, so Ref suffix is there to denote reference-like structure.
Maybe you can find some hints in effective c++ item 4 "Avoid duplication in const and non-const Member function"
I may summarize like following ( it makes you avoid code duplication even if using somewhat ugly cast ):
struct my_class
{
my_class(int x):_x(x){};
const int& method(void) const;
int& method(void);
int _x;
};
const int& my_class::method(void) const //func for const instance
{
return _x;
}
int& my_class::method(void) //func for normal instance
{
return const_cast<int& >(static_cast<const my_class& >(*this).method()) ;
}
int main()
{
my_class a(1);
const my_class b(2);
a.method() = 5;
cout << a.method() << endl;
//b.method() = 4; //b is const, wont compile
cout << b.method() << endl;
return 0;
}
I have the following code:
class STFDataPoint {
public:
virtual ImagePoint get_patch_top_left() const = 0;
virtual ImagePoint get_patch_bottom_right() const = 0;
virtual std::string get_image_filename() const = 0;
virtual ~STFDataPoint() = 0;
};
inline STFDataPoint::~STFDataPoint() {}
class TrainingDataPoint : public STFDataPoint{
private:
int row;
int col;
std::string class_label;
ImagePoint patch_top_left;
ImagePoint patch_bottom_right;
std::string image_filename;
public:
TrainingDataPoint(int row, int col, std::string class_label,
const ImagePoint & top_left,
const ImagePoint & bottom_right,
std::string image_filename);
std::string get_class_label() const;
inline bool operator==(const TrainingDataPoint& other) const{
return other.class_label == this->class_label;
}
inline bool operator!=(const TrainingDataPoint& other) const{
return !(*this == other);
}
virtual ImagePoint get_patch_top_left() const;
virtual ImagePoint get_patch_bottom_right() const;
virtual std::string get_image_filename() const;
};
And I am trying to run the following:
bool do_something(vector<STFDataPoint>& data_point){
return true;
}
int main(int argc, char* argv[]) {
ImagePoint left = ImagePoint(2,3);
ImagePoint right = ImagePoint(2,3);
TrainingDataPoint a = TrainingDataPoint(1,2,"",left, right, "");
vector<TrainingDataPoint> b;
b.push_back(a);
do_something(b);
}
But get the following error:
invalid initialization of reference of type ‘std::vector<STFDataPoint>&’ from expression of type `std::vector<TrainingDataPoint>`
however if I change the signature of do_something() to take in a STFDataPoint (not a vector of them) it runs fine. Can some one please explain why this is and also if there is a work around?
Thanks
Since vector<TrainingDataPoint> is not a subtype of vector<STFDataPoint> you cannot do this. Vectors are not covariant in parameter type.
However you can template do_something to make it work:
template <typename T>
bool do_something(vector<T>& data_point){
//common actions like
ImagePoint leftPatch = data_point[0].get_patch_top_left();
return true;
}
The type vector<TrainingDataPoint> is not the same as vector<STFDataPoint> and there is no conversion between the two. vector<A> is not a base type of vector<B>, even if A is a base of B.
What could work is to have a container of pointers or smart pointers to the base type, and change the function to use that:
bool do_something(vector<std::unique_ptr<STFDataPoint>>& data_point){
return true;
}
std::vector<std::unique_ptr<STFDataPoint>> b;
b.push_back( std::unique_ptr<STFDataPoint>(new TrainingDataPoint(1,2,"",left, right, "") ); // fill with any derived types of STFDataPoint
do_something(b);
Consider the following minimal example.
#include <vector>
class Data
{
std::vector<int>& v;
public:
Data(std::vector<int>& _v) : v(_v) {}
Data(const std::vector<int>& _v) : v(_v) {} // error!
};
int main()
{
std::vector<int> v;
const std::vector<int> c_v;
Data d(v);
Data const_d(c_v);
return 0;
}
This does not compile. The whole output from g++ -Wall below.
const.cpp: In constructor ‘Data::Data(const std::vector<int>&)’:
const.cpp:8:41: error: invalid initialization of reference of type ‘std::vector<int>&’ from expression of type ‘const std::vector<int>’
The reason is clear to me: The const keyword is upset about my cast in line 8. The issue: I really sometimes need the Data class with std::vector, but sometimes with const std::vector. Like having two classes: One for reading into Data, and one for reading from Data. However, I do not like to write two Data classes with almost redundant functions. My questions:
Can you give a nice solution to how I can achieve what I try to do in main()? C++11 solutions are pretty welcome, too :)
Is this the reason for iterator and const_iterator?
const-ness of data members needs to be known at compile time. If you "sometimes" need a reference to a const vector and sometimes non-const, you should create a class hierarchy with the base abstract class containing the common functionality, and inherit it in two Data classes: Data and ConstData. The Data would contain a non-const vector, and ConstData would contain a const vector. This way you would not duplicate any logic, while two separate classes would contain two references of different const-ness.
Here is an example:
class AbstractData {
public:
// Common functions use vect() and const_vect()
void common_function1();
void common_function2();
protected:
virtual vector<int>& vect() const = 0;
virtual const vector<int>& const_vect() const = 0;
};
class Data : public AbstractData {
vector<int>& v;
public:
Data(vector<int>& _v) : v(_v) {}
protected:
vector<int>& vect() const {
return v;
}
const vector<int>& const_vect() const {
return v;
}
};
class ConstData : public AbstractData {
const vector<int>& v;
vector<int> temp;
public:
ConstData(const vector<int>& _v) : v(_v) {}
protected:
vector<int>& vect() const {
return temp; // You can choose to throw an exception instead
}
const vector<int>& const_vect() const {
return v;
}
};
Note that this class hierarchy may need a destructor and various copy constructors, depending on the usage.
The error you got was along the lines of:
foo.cpp: In constructor ‘Data::Data(const std::vector<int>&)’:
foo.cpp:8:44: error: invalid initialization of reference of type ‘std::vector<int>&’ from expression of type ‘const std::vector<int>’
...because you are trying to create a non-const reference to data that you (Data) promised your caller would be treated as const.
Here is a solution which declares a const reference as Data's member:
#include <vector>
class Data
{
const std::vector<int> &v;
public:
Data(std::vector<int>& _v) : v(_v) {}
Data(const std::vector<int>& _v) : v(_v) {} // error!
};
int main()
{
std::vector<int> v;
std::vector<int> c_v;
Data d(v);
Data const_d(c_v);
return 0;
}
Another option is to use a non-reference member instead:
#include <vector>
class Data
{
std::vector<int> v;
public:
Data(std::vector<int>& _v) : v(_v) {}
Data(const std::vector<int>& _v) : v(_v) {} // error!
};
I need someone to show me what is wrong with this code. I don't know what's wrong with it. I know the code doesn't do anything meaningful and it can't be used. I created it only to know how copy constructors work.
class test
{
public:
int* value;
public:
int getvalue()
{return *value;};
test(int x){ value = new int(x);};
test(const test& a)
{
value=new int;
*value = a.getvalue();
};
};
You need to change the declaration of getvalue() to int getvalue() const, since you're trying to call getvalue() on a const reference in your copy constructor.
There is a stray ; after each method definition, so will not compile.
class test { public:
int* value;
public:
int getvalue()
{return *value;}
test(int x){ value= new int(x);}
test(const test& a)
{
value=new int;
*value = a.getvalue();
}
};
Also, I'd avoid 'test' as a class name; depending on your platform if might be a macro or some other in-scpe name. Use "MyTest" or somesuch.
It's been a long time since I last wrote C++, but here goes:
I'm not sure why you're declaring value to be an int pointer; did you mean to make it an int?
class test
{
private:
int value;
public:
test(int x)
{
value = new int(x);
}
int getValue()
{
return value;
}
test(const test & a)
{
value = a.getValue();
}
};
(Posted on behalf of the OP).
I tried making the getvalue() function const and it worked. The problem was that I passed the test class as a const reference and because I didn't declare the getvalue() function const the compiler thought the function was going to change something in that reference.