I have a class Object that I'd like to use as if it were an int. In other words I want to pass this object to functions that accepts int, int* or int& so that the functions "see" actually ony the wrapped int value.
The code below illustrates what I want to do. I was able to write the code for int and int* but I'm not able to write the code for int&.
#include <cassert>
class Object
{
public:
int bla = 0;
int val = 0; // the int being wrapped
Object(int v) : val(v) {};
operator int() const { return val; };
int *operator &() { return &val; };
#if 1
int & operator() { return val; }; // << does not compile
#endif
};
int func(int val) {
return val * 2;
}
void Bar(int* pval, int val) {
*pval = val;
}
void Foo(int & pval, int val) {
pval = val;
}
int main() {
int val;
Bar(&val, 123);
assert(val == 123);
Foo(val, 789);
assert(val == 789);
Object o(8);
assert(func(o) == 2 * 8); // operator int()
Bar(&o, 1234); // int *operator &()
assert(o.val == 1234);
#if 1
Foo(o, 456); // << does not compile
assert(o.val == 456);
#endif
}
If #if 1 is replaced with #if 0, the code works as expected.
Could anybody point me into the right direction so Foo(o, 456); compiles?
The problem is the conversion operator, which you have the wrong syntax for.
It should be
operator int&() { return val; }
Related
Considering the following toy example, where I declare a class which encapsulates ublas from boost libraries:
#include <boost/numeric/ublas/matrix_sparse.hpp>
#include <iostream>
namespace ublas = boost::numeric::ublas;
class UblasEncapsulated {
public:
ublas::compressed_matrix<float>::reference operator()(int i, int j){
std::cout << "Non const reference" << std::endl;
MtrUpdated_ = true;
return mtr_(i, j);
}
ublas::compressed_matrix<float>::const_reference operator()(
int i, int j) const {
std::cout << "Const reference" << std::endl;
return mtr_(i, j);
}
UblasEncapsulated() { MtrUpdated = false; }
private:
ublas::compressed_matrix<float> mtr_(3, 3);
bool MtrUpdated_;
};
int main() {
UblasEncapsulated foo;
foo(2, 0) = 1.0f;
float const foo_float = foo(2, 0);
return 0;
}
I was expecting the output
Non constant reference
Constant reference
But I got
Non constant reference
Non constant reference
What am I doing wrong? How can I properly track when mtr_ could have its values changed?
foo is non-const, so the non-const version of foo.operator() will be called. It doesn't matter how the value it returns is used.
If you really want to know that MtrUpdated_ is only set true if an element is actually assigned to, you will need to use a proxy class:
class UblasEncapsulated {
public:
class proxy {
public:
proxy(UblasEncapsulated* ptr, int i, int j)
: ptr_(ptr), i_(i), j_(j)
{}
proxy& operator=(float f) {
ptr_->MtrUpdated_ = true;
ptr_->mtr_(i_, j_) = f;
return *this;
}
operator float() {
return ptr_->mtr_(i_, j_);
}
private:
UblasEncapsulated* ptr_;
int i_;
int j_;
};
proxy operator()(int i, int j) {
return proxy(this, i, j);
}
ublas::compressed_matrix<float>::const_reference operator() (int i, int j) const {
return mtr_(i, j);
}
UblasEncapsulated()
: mtr_(3, 3),
MtrUpdated_(false)
{}
private:
ublas::compressed_matrix<float> mtr_;
bool MtrUpdated_;
};
Live Demo
Note that you should avoid using a proxy class if you can get away with it since it doesn't play nicely with things like auto or template argument deduction.
The following class should be used as an index into an ordinary array or std::vector. It basically helps with adress calculation for access into an array from a C interface.
class Index
{
public:
int data;
inline void manipulate(Argument arg){
// do some manipulation on data
}
};
What is the right way to achieve an automatic conversion in order to use statements like:
Index myIndex;
...
a[myIndex] = A(...)
f(myIndex); // f is defined as f(int idx){...}
Side question: Will this class use exactly the storage for one int?
You can define an implicit conversion operator:
class Index
{
int data;
public:
// ...
operator int() const { return data; }
};
Side answer: Maybe.
Choose between pest and cholera:
// Explicit Constructor
struct FirstIndex
{
int data;
explicit FirstIndex(const int& data)
: data(data)
{}
operator const int& () const { return data; }
operator int& () { return data; }
};
bool operator == (const FirstIndex& a, const FirstIndex& b) { return a.data == b.data; }
// Explicit Conversion
struct SecondIndex
{
int data;
SecondIndex(const int& data)
: data(data)
{}
explicit operator const int& () const { return data; }
explicit operator int& () { return data; }
};
bool operator == (const SecondIndex& a, const SecondIndex& b) { return a.data == b.data; }
// Nothing Explicit
struct ThirdIndex
{
int data;
ThirdIndex(const int& data)
: data(data)
{}
operator const int& () const { return data; }
operator int& () { return data; }
};
bool operator == (const ThirdIndex& a, const ThirdIndex& b) { return a.data == b.data; }
int main()
{
FirstIndex first(0);
int first_result = 0;
first += 1;
// no match for ‘operator=’
// first = first + 1;
first_result = first;
first_result == first;
SecondIndex second(0);
int second_result = 0;
// error: no match for ‘operator+=’
// second += 1;
// no match for ‘operator+’
// second = second + 1;
// cannot convert ‘SecondIndex’ to ‘int’
// second_result = second;
second_result == second;
ThirdIndex third(0);
int third_result = 0;
third += 1;
third = third + 1;
third_result = third;
// This one is significant
// error: ambiguous overload for ‘operator==’
// third_result == third;
}
I found error in my code that I think should be marked with warning. Compiled with /W4 but it don't show any warning (only about unreferenced formal parameter).
#include <cstdio>
void A(int item, unsigned int count, unsigned team_count)
{
printf("A, count, team count\n");
}
void A(int item, unsigned int count=1, bool is_team=true)
{
printf("A, count, is_team\n");
return A(item, count, is_team ? count : 0);
}
int main()
{
A(0, false); // <- bool to unsigned int
return 0;
}
Here bool is casted to unsigned int. Is there any way to detect that?
Tried Cppcheck but it don't find this.
Here is an example how you can achieve what you want
#include <iostream>
void f( int ) { std::cout << "f( int )" << std::endl; }
void f( bool ) = delete;
int main()
{
f( true );
return 0;
}
Compiler error
prog.cpp:8:10: error: use of deleted function ‘void f(bool)’
f( true );
^
Applied to your code the example will look like
#include <iostream>
void A( int item, unsigned int count, unsigned team_count )
{
std::cout << "A, count, team count" << std::endl;
}
void A( int item, unsigned int count = 1, bool is_team = true )
{
std::cout << "A, count, is_team" << std::endl;
return A( item, count, is_team ? count : 0 );
}
void A( int, bool ) = delete;
int main()
{
A( 0, false );
return 0;
}
Error:
prog.cpp:18:14: error: use of deleted function ‘void A(int, bool)’
A( 0, false );
^
The standard says this is acceptable §4.7/p4 Integral Conversions:
If the source type is bool, the value false is converted to zero and the value true is converted to one.
Regarding how to detect this (since it's not an error) and depending on your use-case, you could either do some clang-tooling yourself or write a wrapper with some template deduction magic on the lines of:
#include <cstdio>
#include <type_traits>
template<typename T, typename U>
void A(int item, T, U) {
static_assert(!std::is_same<T, unsigned int>::value ||
(!std::is_same<U, unsigned int>::value &&
!std::is_same<U, bool>::value),
"Something was wrong");
}
template<>
void A(int item, unsigned int count, unsigned int team_count)
{
printf("A, count, team count\n");
}
template<unsigned int count = 1, bool is_team = true>
void A(int item, unsigned int, bool)
{
printf("A, count, is_team\n");
return A(item, count, is_team ? count : 0);
}
int main()
{
// A(0, false); - not acceptable
// A(0, 22); - not acceptable
A(0, static_cast<unsigned int>(2), false);
A(0, static_cast<unsigned int>(33), static_cast<unsigned int>(45));
return 0;
}
Example
Note that the base template deduction mechanism doesn't require C++11, although some functions used above do.
A very safe way to prevent such things is to wrap your count types in classes without implementing automatic conversions.
class Count
{
private:
int m_count;
public:
explicit Count(int count) : m_count(count)
{
assert(m_count >= 0);
}
int Get() const { return m_count; }
};
class TeamCount
{
private:
int m_count;
public:
explicit TeamCount(int count) : m_count(count)
{
assert(m_count >= 0);
}
int Get() const { return m_count; }
};
// ...
void A(int item, Count count, TeamCount team_count);
void A(int item, Count count = Count(1), bool is_team = true);
// ...
A(0, false); // <- compiler error
A(0, TeamCount(0), false); // <- compiler error
A(0, Count(0), false); // OK
You can do a similar thing with your other primitive type parameters.
There is something that is troubling my brain since a moment: I am trying to overload the [] operator based on the return type. Here is what I need to do:
class A {
private:
double* data_;
int N_;
public:
A (N=0):N_(N){
data_ = new double[N];
}
~A {delete[] data_;}
double operator[] (const int i) {
return data_[i];
}
double* operator[] (const int i) {
return &data[i]; // for example; in fact here i need to return some block of data_
}
};
This code won't compile; and that is my problem. Can someone help me to solve this problem?
PS: I know how to overload normal functions on the return type for example:
int foo ();
string foo ();
I used some tricks that I read in this forum. In this way:
struct func {
operator string() { return "1";}
operator int() { return 2; }
};
int main( ) {
int x = func(); // calls int version
string y = func(); // calls string version
double d = func(); // calls int version
cout << func() << endl; // calls int version
func(); // calls neither
}
Thank you.
Two method overloads must have different signatures. The return type is not part of the signature of a method.
You can use the same "trick" that you use for functions, that is use a proxy object with conversion operators:
class A
{
private:
double* data_;
int N_;
public:
A (int N = 0)
: N_(N), data_(new double[N])
{}
~A() { delete[] data_; }
struct proxy
{
int i;
double * data;
operator double() const
{
return data[i];
}
operator double*()
{
return &data[i];
}
operator double const *() const
{
return &data[i];
}
};
proxy operator[] (int const i) {
proxy p { i, data_ };
return p;
}
proxy const operator[] (int const i) const {
proxy p { i, data_ };
return p;
}
};
int main()
{
{
A a(12);
double d = a[0];
double * pd = a[0];
}
{
A const ca(12);
double d = ca[0];
//double * pd = ca[0]; // does not compile thanks to overloads on const
double const * pcd = ca[0];
}
}
However, I would argue that this is a terrible idea. Having your operator[] return either a value or a pointer to this value is guaranteed to confuse the users of your class, in addition to making it impractical to use in expressions where both types are possible. For instance, std::cout << a[0]; would not compile (ambiguous overloads).
Probably you need something like that:
class A {
private:
double* data_;
int N_;
... // other stuff
public:
double operator[] (const int i) const { // note const here
return data_[i];
}
double& operator[] (const int i) { // note reference here
return data_[i];
}
};
also operator should be public to have a sense.
The following code compiles (without warnings) on both clang++-2.9 and g++-4.6. However, the g++ binary Seg Faults, while the clang++ binary runs as intended.
What is the proper way to access template class data members through pointers when overloading []?
Here's the code:
#include <iostream>
template <typename T>
class A {
private:
T val1;
T val2;
public:
T& getVal1() { return val1; }
void setVal1(T aVal) { val1 = aVal; }
T& getVal2() { return val2; }
void setVal2(T aVal) { val2 = aVal; }
};
template <typename T>
class B {
private:
A<T>* aPtr;
public:
A<T>* getAPtr() { return aPtr; }
T& operator[](const int& key) {
if(key == 0) { T& res = getAPtr()->getVal1();
return res; }
else { T& res = getAPtr()->getVal2();
return res; }
}
};
int main()
{
B<int> foo;
foo[0] = 1;
int x = foo[0];
std::cout << foo[0] << " " << x << std::endl; // 1 1
}
You are returning a reference to a local variable (res). The reference won't be valid after returning from operator[]. It could be overwritten by other stuff. What really happens is Undefined: that is why compilers are allowed to eat your children or grow a moustache: Undefined Behaviour
You probably want to return by value.
Edit
Since you have a setter, you don't need the reference: See the solution live at http://ideone.com/oxslQ
Note: there was another problem with aPtr not being initialized. I proposed a simple constructor for that. _You might want to initialize this from elsewhere OR you need
assignment and copy constructors
or use a shared_ptr for aPtr
.
#include <iostream>
template <typename T>
class A
{
private:
T val1;
T val2;
public:
T getVal1()
{
return val1;
}
void setVal1(T aVal)
{
val1 = aVal;
}
T getVal2()
{
return val2;
}
void setVal2(T aVal)
{
val2 = aVal;
}
};
template <typename T>
class B
{
private:
A<T>* aPtr;
B(const B&); // TODO , disallow for now
B& operator=(const B&); // TODO , disallow for now
public:
B() : aPtr(new A<T>()) {}
~B() { delete aPtr; }
A<T>* getAPtr()
{
return aPtr;
}
T operator[](const int& key)
{
if(key == 0)
{
T res = getAPtr()->getVal1();
return res;
}
else
{
T res = getAPtr()->getVal2();
return res;
}
}
};
int main()
{
B<int> foo;
foo.getAPtr()->setVal1(1);
int x = foo[0];
std::cout << foo[0] << " " << x << std::endl; // 1 1
}
If you want to return by ref, then your A::getValX() functions should also return by ref, and your res variable inside B::operator should also be T& instead of T:
#include <iostream>
template <typename T>
class A {
private:
T val1;
T val2;
public:
T& getVal1() { return val1; }
void setVal1(T aVal) { val1 = aVal; }
T& getVal2() { return val2; }
void setVal2(T aVal) { val2 = aVal; }
};
template <typename T>
class B {
private:
A<T>* aPtr;
public:
A<T>* getAPtr() { return aPtr; }
T& operator[](const int& key) {
if(key == 0) { T& res = getAPtr()->getVal1();
return res; }
else { T& res = getAPtr()->getVal2();
return res; }
}
};
int main()
{
B<int> foo;
foo[0] = 1;
int x = foo[0];
std::cout << foo[0] << " " << x << std::endl; // 1 1
}
(Note that it will still crash at runtime, since aPtr isn't initialized anywhere.)
Your original code returns a reference to the local variable res, not to A::val1 / A::val2 as you probably intended. If res is a non-reference variable, then it will be a simple copy of the val1 / val2 value, that is only valid for inside the scope (in this case the function) where it was declared. So you need a reference here.