I'm having trouble with overloading operator() with a const version:
#include <iostream>
#include <vector>
using namespace std;
class Matrix {
public:
Matrix(int m, int n) {
vector<double> tmp(m, 0.0);
data.resize(n, tmp);
}
~Matrix() { }
const double & operator()(int ii, int jj) const {
cout << " - const-version was called - ";
return data[ii][jj];
}
double & operator()(int ii, int jj) {
cout << " - NONconst-version was called - ";
if (ii!=1) {
throw "Error: you may only alter the first row of the matrix.";
}
return data[ii][jj];
}
protected:
vector< vector<double> > data;
};
int main() {
try {
Matrix A(10,10);
A(1,1) = 8.8;
cout << "A(1,1)=" << A(1,1) << endl;
cout << "A(2,2)=" << A(2,2) << endl;
double tmp = A(3,3);
} catch (const char* c) { cout << c << endl; }
}
This gives me the following output:
NONconst-version was called - - NONconst-version was called - A(1,1)=8.8
NONconst-version was called - Error: you may only alter the first row of the matrix.
How can I achieve that C++ call the const-version of operator()? I am using GCC 4.4.0.
The overloading looks fine but you never call it on a const object. You can try this:
void foo(const Matrix& A) {
cout << "A(1,1)=" << A(1,1) << endl;
}
Matrix A(10,10);
foo(A);
This gives you:
- const-version was called - A(1,1)=0
The object you are calling the method on must be const, e.g.
cout << "A(2,2)=" << (*static_cast<const Matrix*>(&A))(2,2) << endl;
Generally, you can't call a const or non-const version of a function depending on what you do with the return value. If you want to emulate similar functionality, you can try returning some proxy that will switch the behaviour depending on what you do with it:
class Proxy
{
Matrix& m;
int x, y;
public:
...
// mutating operations
operator double&() { check(); return m.index(x,y); }
double& operator=(double d) { check(); return m.index(x,y)=d; }
// ... other mutating operations (+=, ...) analogously
// nonmutating ops
operator double() { return m.const_index(x, y); }
operator const double&() // ... same
};
Proxy Matrix::operator(int x, int y)
{
return Proxy(*this, x, y);
}
Assuming check() is your check for legal mutation (could be integrated in index()) and index() and const_index() are methods in Matrix that give a reference or const reference to a particular place.
Use const_cast<>() or make your instance const.
I'm guessing maybe you want to be sure the operator returns a const double? Maybe you should just provide the const version, not the other one.
You have different methods with different functionality, so give them different names. Then you don't need to have a const object just to call what you want.
You can still make operator() const call the alternative function in case you do happen have a const object. But the alternative functionality should be put in a function with a descriptive name.
As for getting a const handle to an object, use static_cast< const Matrix & >( A ).
Related
Here's my problem, I have a class Foo() which holds two doubles, its value and an extra one:
class Foo {
public:
Foo(double value, double extra) :
value_(value), extra_(extra) {
}
operator double() const
{
return value_;
}
double extra() const {
return extra_;
}
private:
double value_;
double extra_;
};
I want to be able to access the value_ as if it was a literal double, hence the double() operator, but I also want to access its extra value.
Now say I have a template class that holds a Foo and a literal double, and can access the value and extra value of both (extra value of literal doubles should always be 1):
template <typename T1, typename T2>
class Testing {
public:
Testing(T1 a, T2 b) :
a_(a), b_(b) {
}
void test() {
double valA = a_;
double valB = b_
std::cout << valA << " " << valB << std::endl;
double extraA = a_->extra();
double extraB = b_->extra();
std::cout << extraA << " " << extraB << std::endl;
}
private:
T1 a_;
T2 b_;
};
This obviously doesn't compile, because double doesn't have any extra() method.
Would there be any way to implement this and say something (in compile time) like, if either type T1 or T2 doesn't have an extra() method, simply use 1 when calling extra?
The only thing I've come up with that works are these operators for Foo (which I wouldn't use either way):
double operator*(const double& rhs) const
{
return extra() - 1;
}
double operator/(const double& rhs) const
{
return value_;
}
(I had to use the division operator instead of double() to avoid ambiguity)
Combined with this:
void test() {
double valA = a_/1;
double valB = b_/1;
std::cout << valA << " " << valB << std::endl;
double extraA = a_*0 + 1;
double extraB = b_*0 + 1;
std::cout << extraA << " " << extraB << std::endl;
}
But I don't think this is very elegant. A more "readable" option could be to have a wrapper class around double that has the extra() method, but considering I would be working with many of these values I don't like the memory overhead. EDIT: This wouldn't work, I need the double to be literal.
Thanks for the help, I would also be intereted in knowing whether there are would be any performance issues with the aforementioned possible solution.
To me it sounds like you could do several things. Either Testing should not be a template and only have Foo members, so that you can use a converting constructor for Foo,
Foo(double value, double extra = 1);
to allow implicit conversion from a single double. Or, as you say, another Foo-like class whose extra() simply returns 1.
Otherwise, you could obtain the extra value using functions like these:
template<typename T>
double extra(T const&) { return 1; }
double extra(Foo const& foo) { return foo.extra(); }
Hello I wanted to know if it was possible to do a thing like this ? // THANKS ! :)
struct PET
{
const char* pet;
const int age;
};
bool Sort(const PET& first, const PET& second)
{
return first.pet < second.pet;
}
void Foo(const std::vector<PET> pets)
{
std::sort(pets.begin(), pets.end(), Sort); /* Does not work */
std::cout << pets[0].pet;
std::cout << pets[0].age;
}
I completely agree with # Ulrich Eckhardt.
You cannot sort the vector as because the elements of your vector are not assignable.
I think, you might have gone confused with usage of const.
There is no need to make the structure variables const. The parameter of the custom sort function are generally kept as const because they should not be modifiable. This is a pattern which ensures safe coding practice.
Also, if you are using C++, I would suggest to use std::string instead of char*, as std::string is a cleaner, safer way to go because it removes the burden of memory management from the programmer.
Have a look at the working implementation, without use of const:
#include <string.h>
#include<iostream>
#include<vector>
#include<algorithm>
struct PET
{
std::string name;
int age;
};
bool compare(const struct PET& a, const struct PET& b){
return (a.name.compare(b.name) <= 0) ? true : false;
}
int main(){
std::vector<struct PET> vec(3);
vec[0].name = "dog";
vec[0].age = 3;
vec[1].name = "cat";
vec[1].age = 1;
vec[2].name = "bird";
vec[2].age = 2;
sort(vec.begin(), vec.end(), compare);
for(int i=0;i<3;i++){
std::cout<<vec[i].name<<" "<<vec[i].age<<std::endl;
}
return 0;
}
As #Deepak Tatyaji Ahire and #Ulrich Eckhardt said, you can't do what you wrote in your code.
const int can't be a variable. It is a constant for definition :)
The vector you wrote in your code can't be built that way.
I did not understand what you wanted to do with the "sort" function, I wrote the following to code, maybe it could help:
#include<iostream>
#include<vector>
struct PET
{
const char* pet;
int age;
PET(const char* c, int a) : pet(c) , age(a) {}
};
void Foo(PET &p, std::vector<PET> &v)
{
v.push_back(p);
/*do something here if needed*/
}
int main()
{
std::vector<PET> vect;
PET cat("Cat", 5);
PET dog("Dog", 10);
PET bird("Bird", 2);
Foo(cat, vect);
Foo(dog, vect);
Foo(bird, vect);
/*this is not elegant, you could define a function that give a list of
({Animal, age},...) to vector and then pushes back all these elements to the vector*/
for(int i=0; i<3; i++) std::cout<< vect[i].pet << ' ' << vect[i].age << std::endl; //std::cout << vect; if you are using an operator << overload
/*to overload the << operator in order to able to print the vector of struct PET:
std::ostream & operator << (std::ostream &os, std::vector<PET> &p)
{
os << "<";
for (int i = 0; i < p.size(); i++) {
os << p[i].pet;
os << ", ";
os << p[i].age;
if (i != p.size() - 1)
os << " - ";
}
os << ">\n";
return os;
}
*/
return 1;
}
AFAIK, there's no way to directly compare structures without defining their comparator.
Though in C++20, it introduces three-way comparison and you might be allowed to declare the Default comparisons by a single line. Very convenient. Unfortunately, there haven been no compiler implementing this feature.
For now, you have to manually define the comparator
inline bool cmp(const PET &lhs, const PET &rhs)
{
return std::strcmp(lhs.pet, rhs.pet)<0;
}
and pass it to std::sort
Take a look at this simple array class
class Array {
const unsigned int _size;
int _array[100];
public:
Array() : _size(100) {
for(unsigned int i = 0; i < _size; i++)
_array[i] = 0;
}
int& operator[](unsigned int index) {
cout << "normal operator[].\n";
return _array[index];
}
const int& operator[](unsigned int index) const {
cout << "const operator[].\n";
return _array[index];
}
};
int main()
{
Array a;
a[3] = 1;
cout << a[3] << "\n";
system("pause");
return 0;
}
The "normal operator[]" line is executed twice, though I would expect the second call (cout << a[3] << "\n";) to be using the const version of the overloaded operator, because it doesn't change the array itself.
Why is that? Is there a way to force the const version to be called as I wish?
When you have an overloaded const version of a method, the const version will be called when the object is const. For example:
#include <iostream>
using namespace std;
class MyClass
{
public:
void foo()
{
cout << "foo()" << endl;
}
void foo() const
{
cout << "foo() const" << endl;
}
};
int main()
{
MyClass a;
const MyClass b;
a.foo();
b.foo();
return 0;
}
will call the normal foo() for the object a, and the const version for the object b.
In your case, you just have to avoid trying to assign to the const version. For example:
Array a;
const Array b;
a[3] = 1;
// b[3] = 1; // error
cout << a[3] << "\n";
cout << b[3] << "\n";
works fine. But if you try to make the assignment to b, you get a compile error.
std::ostream &operator<<(int x) doesn't take its parameter as const (because const isn't useful when passing by value), so the non-const operator[] can be called.
So, when will const operator[] be called?
It is true that a const vector variable declaration is almost always useless aside from some edge cases. The primary reason const operator[] is important, and the most often you will see it used, is calling it on a reference parameter.
int readStuff(const std::vector<int> &dontMutateMe) {
return dontMutateMe[42]; // const
}
Constant reference parameters are valuable, and this code wouldn't work without const operator[].
I am almost sure that this cannot be done, but I will ask anyway.
I have to use a C based library, which defines a numeric vector as array of floats, and lots of arithmetic functions to use them.
I want to create a trivial class that can be easily casted to that type, with the addition of useful operators. Let's see a MWE:
#include <iostream>
using vector_type = float[3];
class NewType
{
public:
float& operator [](std::size_t i) { return v[i]; }
const float& operator [](std::size_t i) const { return v[i]; }
operator vector_type& () { return v; }
vector_type* operator & () { return &v; }
private:
vector_type v;
};
int main()
{
NewType t;
t[0] = 0.f; t[1] = 1.f; t[2] = 2.f;
const vector_type& v = t;
std::cout << "v(" << v[0] << "," << v[1] << "," << v[2] << ")" << std::endl;
return 0;
}
This works flawlessly. The problem arises when we start using arrays. Let's write a new main function:
int main()
{
constexpr std::size_t size = 10;
vector_type v1[size]; // OK
NewType v2[size]; // OK
vector_type* v3 = v2; // No way, NewType* cannot be
// converted to float (*)[3]
vector_type* v4 =
reinterpret_cast<vector_type*>(v2); // OK
return 0;
}
The reinterpret_cast works, but it makes the code less readable and the conversion between vector_type and NewType not transparent.
As far as I know, it is not possible, according to C++11 and C++14 standards, to make the NewType class implicitly castable when using arrays. Is it completely true? Are there any sort of caveats that allow this convertion?
P.s.: Please, do not start commenting about the risks of using reinterpret_cast and so on. I am aware of the risks, I know that the compiler could add some padding, and I already have some static_assert checks to avoid memory problems.
[Edit] I want to make the problem easier to understand. Let's make a different example:
struct original_vector
{
float x;
float y;
float z;
};
class NewType : public original_vector
{
public:
/* Useful functions here */
};
If this would be my case, everything would be easy! The type used in the C library would be original_vector, and I could create a derived class and I could add any sort of method.
The problem is that, in my real case, the original_vector is not a class/struct, but a raw array! And obviously, I cannot inherit it. Maybe now it is more clear the reason I am asking this question. ;)
I think that it is not the best solution, but it is the best I can think using C++14 capabilities. Maybe, if runtime-sized member allocation is introduced in future standards (the proposal for C++14 has been rejected), a better solution will be possible. But for now...
#include <iostream>
#include <memory>
#include <cassert>
using vector_type = float[3];
class NewType
{
public:
float& operator [](std::size_t i) { return v[i]; }
const float& operator [](std::size_t i) const { return v[i]; }
operator vector_type& () { return v; }
vector_type* operator & () { return &v; }
private:
vector_type v;
};
class NewTypeArray
{
public:
NewTypeArray() : size(0), newType(nullptr) {}
NewTypeArray(std::size_t size) : size(size) { assert(size > 0); newType = new NewType[size]; }
~NewTypeArray() { if(size > 0) delete[] newType; }
NewType& operator[](std::size_t i) { return newType[i]; }
operator vector_type* () { return static_cast<vector_type*>(&newType[0]); }
private:
std::size_t size;
NewType* newType;
};
static_assert(sizeof(NewType) == sizeof(vector_type) and sizeof(NewType[7]) == sizeof(vector_type[7]),
"NewType and vector_type have different memory layouts");
Obviously, the NewTypeArray could be modified, implementing vector-oriented methods, move constructor and assignment (like in my real-case code).
Instances of NewTypeArray could be directly passed to functions which takes vector_type* as argument and, thanks to the static_assert, there should not be any sort of problems with memory management.
#include <iostream>
#include <vector>
typedef std::vector<float> vector_type;
class NewType: public vector_type
{
public:
void MyMethod() {std::cout << "extending the vector type!" << std::endl;}
};
int main()
{
NewType myNewTypeVector[10];
myNewTypeVector[0] = NewType();
myNewTypeVector[0].push_back(1);
myNewTypeVector[0].push_back(2);
vector_type* p = myNewTypeVector;
std::cout << "Content of my_vector index 0: " << p[0][0] << std::endl;
std::cout << "Content of my_vector index 1: " << p[0][1] << std::endl;
std::cout << "Content of myNewTypeVector index 1: " << myNewTypeVector[0][1] << std::endl;
return 0;
}
I have these template functions for use inline on device with cuda
template <class T> __device__ inline T& cmin(T&a,T&b){return (a<b)?(a):(b);};
template <class T> __device__ inline T& cmax(T&a,T&b){return (a>b)?(a):(b);};
In the code I have
cmin(z[i],y[j])-cmax(x[i],z[j])
for int arrays x,y,and z. I get the error:
error: no instance of function template "cmax" matches the argument list
argument types are: (int, int)
I get the error for cmax but not cmin. If I replace the cmax line with
#define cmax(a,b) ((a)>(b))?(a):(b)
that works just fine, but I don't want #defines, they are problematic. What the heck is going on here?
EDIT:
here is the full calling function. times is typedef int.
__global__ void compute_integral_y_isums(times * admit, times * discharge, times * Mx, times * isums, ar_size N){
// computes the sums for each j
// blocks on j,
// threads on i since we will be summing over i.
// sumation over J should be handled by either a different kernel or on the cpu.
ar_index tid = threadIdx.x;
ar_index i = blockIdx.x; // summing for patient i
ar_index j = threadIdx.x; // across other patients j
__shared__ times cache[threadsPerBlock];
times Iy = 0;
while(j<N){
// R code: max(0,min(Mx[i],d3[j,'Discharge.time'])-max(d3[i,'Admission.time'],Mx[j]))
times imin = cmin(Mx[i],discharge[j]);
times imax = cmax(admit[i],Mx[j]);
Iy += cmax(0,imin-imax);
j += blockDim.x;
}
cache[tid] = Iy;
__syncthreads();
// reduce
/***REMOVED***/
}
Iy += cmax(0,imin-imax);
is not legal. You can't bind the literal 0 to an int& reference (but you can to a const int& reference).
If either x or z is a const array, their element type will be const int, which is not convertible to int&.
Try with:
template<class T> __device__ inline T cmin(const T& a, const T& b)
{
return (a < b ? a : b);
}
template<class T> __device__ inline T cmax(const T& a, const T& b)
{
return (a > b ? a : b);
}
If T is always a primitive type like int, you can even pass the parameters by value:
template<class T> __device__ inline T cmin(T a, T b)
{
return (a < b ? a : b);
}
template<class T> __device__ inline T cmax(T a, T b)
{
return (a > b ? a : b);
}
EDIT: #aschepler has the right answer.
You should be careful in returning a reference, if your functions also take references as arguments. You might return a reference to a temporary! Like in:
cmin(0,imin-imax);
which is probably ok for int and float, but dangerous for non-PODs.
Try to reverse the definition order please.
template <class T> __device__ inline T& cmax(T&a,T&b){return (a>b)?(a):(b);};
template <class T> __device__ inline T& cmin(T&a,T&b){return (a<b)?(a):(b);};
cmax then cmin. What is the outpout then ?
Your cmax and cmin are taking non-const reference to the elements. Maybe your arrays are declared as const?
Hard to tell, because the example is not complete.
Maybe you already have some active defines which pollute you namespace?Try renaming cmin and cmax, or #undef cmin and #undef cmax. Or run g++ -E to see the de-macrofied code.
Or add :: namespace specifier:
::cmin(z[i],y[j])-::cmax(x[i],z[j])
Anyway, you only need all the () in defines. Nicer:
template __device__ T& cmin(const T&a,const T&b){return a<b?a:b;};
And you probably do not need the inline for a template function neither.
To clarify my comment on the initial question: Yes, one should be careful if ona just passes through a reference from a parameter. Here is a complete illustration:
#include <iostream>
struct Thing {
int data;
Thing() { data = 42; }
Thing(int val) { data = val; }
Thing(const Thing& oth) { data = oth.data; }
Thing& operator=(const Thing& oth)
{ if(this!=&oth) this->data = oth.data; return *this; }
~Thing() { data = 0; } // clear, destroy, release...
};
bool operator<(const Thing &a, const Thing &b) { return a.data
const T& refmin(const T &a, const T &b) // return a ref
{
return a < b ? a : b;
}
template
const T copymin(const T &a, const T &b) // return a copy
{
return a < b ? a : b;
}
followed by
int main(int argc, const char* [])
{
Thing a(11);
Thing b(88);
std::cerr << "Simple operation:" << std::endl;
const Thing c = a + b;
std::cerr << " c:" << c.data << " should be 99" << std::endl;
std::cerr << "Working on temp expression (BAD):" << std::endl;
const Thing &x = refmin(c, b-a); // '&x' will be gone after ';'
// the next line might crash:
std::cerr << " x:" << x.data << " should be 77" << std::endl;
std::cerr << "Working explicit side variable (OK):" << std::endl;
const Thing &d = b-a;
const Thing &y = refmin(c, d); // '&y' is now same as '&d'
std::cerr << " d:" << d.data << " should be 77" << std::endl;
std::cerr << " y:" << y.data << " should be 77" << std::endl;
std::cerr << "Working on a copy (OK):" << std::endl;
const Thing &z = copymin(c, b-a);
std::cerr << z:" << z.data << " should be 77" << std::endl;
return 0;
}
The output is:
$ ./minreftest
Simple operation:
c:99 should be 99
Working on temp expression (BAD):
x:0 should be 77
Working explicit side variable (OK):
d:77 should be 77
y:77 should be 77
Working on a copy (OK):
z:77 should be 77
On some machines it might even segfault, I guess. In Things destructor I reset data to 0, but one could easily imagine more there.
So, when we do the BAD refmin call, we return a reference to a temporary. Which is destroyed after the ;. So, when we try to output &x, it's already gone.