My code is as follows:
class Foo{
public:
int operator()(int i)
{
return 1;
}
int operator++(int i)
{
return 1;
}
};
int main()
{
Foo foo;
int a = foo++;
int b = foo(0);
float c = 0;
}
The problem is that I am not able to watch foo(0):
foo++ is visible normally.
I think the reason is that overloaded function call operator becomes a FunctionObject type (see here https://en.cppreference.com/w/cpp/language/operators).
Is it possible to watch it?
As n-1-8e9-wheres-my-share-m commented, foo.operator()(0) works for me:
Related
struct P {
int x, y;
friend P operator-(P u, P v) { return {u.x - v.x, u.y - v.y}; }
friend int cross(P u, P v) { return u.x * v.y - u.y * v.x; }
int cross(P u, P v) const { return cross(u - *this, v - *this); }
};
The method is an infinite loop (it will call itself instead of the friend).
Is there any way to get around this issue without changing the interface (the names)?
It is possible with a declaration inside the member function:
#include <stdio.h>
struct Foo {
friend int add(int a, int b) {
return a + b;
}
int add(int a, int b) const {
int add(int, int); // function declaration
return add(a, b); // call that declared function
}
};
int main() {
Foo foo;
printf("%d", foo.add(1, 2)); // prints 3
}
Demo
You can't have two member functions with the same name and the same signature in a struct (or class).
One solution is to move the friend function out of the struct, so that it can be referred to with a global namespace specifier ::
#include <iostream>
int cross(int i) { return 42; }
struct P {
friend int cross(int i);
int cross(int i) const { return ::cross(i - 1); }
};
int main() {
P p = {};
std::cout << p.cross(7) << std::endl;
}
The original code produced two warnings, very descriptive:
1 > 1.cpp(6, 25) : warning C4514 : 'cross' : unreferenced inline function has been removed
1 > 1.cpp(7) : warning C4717 : 'P::cross' : recursive on all control paths, function will cause runtime stack overflow
Re: without changing the interface (the names) - you could simply rename your friend function and even make it private; it is not a part of the interface.
Ayxan Haqverdili's answer seems to be cleanest possible, and abides by the ISO. However, pre-gcc 11.0 and pre-clang 8.0 appear to have bugs that cause this to fail.
Luckily in this case there's an alternative that uses argument-dependent lookup:
#include <iostream>
class Foo
{
friend int Bar (Foo)
{
return 13;
}
friend int RedirectToBar (Foo);
public:
int Bar (Foo)
{
return RedirectToBar(Foo());
}
};
int RedirectToBar (Foo)
{
return Bar(Foo());
}
int main ()
{
std::cout << Foo().Bar(Foo()) << std::endl;
}
Live demo
Keep in mind that this only works because some of the arguments to the function are an associated class.
If that's not the case and you really want to keep this design and really need compatibility with older compilers, then we can add in a dummy associated class without breaking the interface by adding it as a default parameter:
#include <iostream>
int RedirectToBar ();
class Foo
{
struct Key {};
friend int Bar (Key = Key())
{
return 13;
}
friend int RedirectToBar ();
public:
int Bar ()
{
return RedirectToBar();
}
};
int RedirectToBar ()
{
return Bar(Foo::Key());
}
int main ()
{
std::cout << Foo().Bar() << std::endl;
}
Live demo
However, it's important to add that all of this is a big code smell. Although I don't know the real-world problem of the OP, this seems like a terrible hack to get around bad design choices.
I ended up using this solution similar to Peter's and Yksisarvinen's:
struct P {
int x, y;
friend P operator-(P u, P v) { return P{u.x - v.x, u.y - v.y}; }
friend int cross(P u, P v);
int cross(P u, P v) const;
};
int cross(P u, P v) { return u.x * v.y - u.y * v.x; }
int P::cross(P u, P v) const { return ::cross(u - *this, v - *this); }
Not quite sure yet why the compiler doesn't find ::cross if I write it inside of P.
Note, there is one potential drawback: we have to specify the return type of both functions (can't have it deduced with auto), but this was not needed in this case.
I have the following code:
class example {
int x;
inline void operator=(int value) { x = value; }
};
int main() {
example foo { 100 };
int bar = foo;
}
The int bar = foo; obviously doesn't work, because I'm trying to assign a variable of type example to a variable of type int.
Is it possible to retrieve the x variable without using a getter function and without using operator.? If so, is it still possible to do purely by code inside the struct, and keeping the int bar = foo; as is?
Add a conversion function to allow implicit conversion
struct example {
int x;
inline void operator=(int value) { x = value; }
operator int() const
{
return x;
}
};
int main() {
example foo { 100 };
int bar = foo;
}
#include <iostream>
int foo(int i)
{
const auto a = [&i](){ i = 7; return i * i; };
a();
return i;
}
int main()
{
std::cout << foo(42) << std::endl;
return 0;
}
This compiles( g++ -std=c++11 -Wall -Wextra -Wpedantic main.cpp ) and returns 49. Which is surprising to me, because by declaring a to be a constant object, I would have expected i to be referenced as const int&. It clearly isn't, why?
Lambdas are just like non-lambdas, except their implementation details are hidden. Therefore, it may be easier to explain using a non-lambda functor:
#include <iostream>
int foo(int i)
{
struct F {
int &i;
int operator()() const { i = 7; return i * i; }
};
const F a {i};
a();
return i;
}
int main()
{
std::cout << foo(42) << std::endl;
return 0;
}
F has a int & reference member i. const F cannot have its instance data modified, but a modification to i isn't a modification to its instance data. A modification to its instance data would be re-binding i to another object (which isn't allowed anyway).
[&i](){ i = 7; return i * i; }
is mainly equivalent to
class Lambda
{
public:
Lambda(int& arg_i) : i(arg_i) {}
auto operator() () const { i = 7; return i * i;}
private:
int& i;
};
And so then you have:
const Lambda a(i);
a();
And the const Lambda won't promote its member to const int& i; but int& const i; which is equivalent to int& i;.
When you capure i it is captured as the type it is.
So internally it has a int&. A const before the variable declaration of the closure does not change anything for the lambda.
You have 2 options to solve this:
const int i = 5;
auto b = [&i]() { i++; }; //error on i++
This way a const int& will be captured.
If you cannot change i for some reasons you can do this in c++14
int i = 5;
auto b = [i = static_cast<const int&>(i)]() { i++; }; //error on i++
This casts the int& to a const int& and will be stored as such in the lambda. Though this is way more verbose as you can see.
In the code you gave:
int foo(int i)
{
const auto a = [&i](){ i = 7; return i * i; };
a();
return i;
}
You are not assigning after you initialized your constant lambda function. Therefore, const doesn't mean much in this context.
What you have declared as const it isn't the context of your anonymous function or lambda exspression and its parameters, but only the reference at that lambda expression: const auto a.
Therefore, you cannot change the value of your lambda expr reference a because it is const, but its parameter passed by reference, &i, can be changed within the context of lambda expression.
If I understand correctly, the question is why you're allowed to mutate i even though a is const and presumably contains a reference to i as a member.
The answer is that it's for the same reason that you're allowed to do this on any object - assigning to i doesn't modify the lambda instance, it modifies an object it refers to.
Example:
class A
{
public:
A(int& y) : x(y) {}
void foo(int a) const { x = a; } // But it's const?!
private:
int& x;
};
int main()
{
int e = 0;
const A a(e);
a.foo(99);
std::cout << e << std::endl;
}
This compiles, and prints "99", because foo isn't modifying a member of a, it's modifying e.
(This is slightly confusing, but it helps to think about which objects are being modified and disregard how they're named.)
This "const, but not really" nature of const is a very common source of confusion and annoyance.
This is exactly how pointers behave, where it's more obviously not wrong:
class A
{
public:
A(int* y) : x(y) {}
void foo(int a) const { *x = a; } // Doesn't modify x, only *x (which isn't const).
private:
int* x;
};
I would like the compiler to enforce const-ness of an lvalue (non-reference) but don't know if this is possible in C++. An example:
int foo() { return 5; }
int main() {
// Is there anything I can add to the declaration of foo()
// that would make the following cause a compile-error?
int a = foo();
// Whereas this compiles fine.
const int a = foo();
}
This is not really possible with something like an int because you need to give access to read the int and if they can read the int then they can copy it into a non-const int.
But from your comments it sounds like what you have in reality is not an int but a more complex user defined type, some sort of container perhaps. You can easily create an immutable container. This container could be a wrapper, or alternative implementation of your existing container. It then doesn't matter if the caller uses a const or non-const variable it is still immutable.
class MyClass {
std::vector<int> data;
public:
MyClass(size_t size) : data(size) {}
int& operator[](size_t index) { return data[index]; }
int operator[](size_t index) const { return data[index]; }
size_t size() const { return data.size(); }
};
class MyClassImmutable {
MyClass mc;
public:
MyClassImmutable(MyClass&& mc) : mc(std::move(mc)){}
int operator[](size_t index) const { return mc[index]; }
size_t size() const { return mc.size(); }
const MyClass& get() const { return mc; }
};
MyClassImmutable foo() {
MyClass mc(100);
mc[10] = 3;
return mc;
}
void func(const MyClass& mc);
int main() {
MyClassImmutable mci = foo();
std::cout << mci[10] << "\n"; // Can read individual values
//mci[10] = 4; // Error immutable
func(mc.get()); // call function taking a const MyClass&
}
Live demo.
Of course there is nothing to stop the caller from copying each and every value from your immutable container and inserting them into a mutable container.
Edit: An alternative approach might be to return a smart pointer-to-const. The only downside is you have to pay for a dynamic memory allocation:
std::unique_ptr<const MyClass> foo() {
auto mc = std::make_unique<MyClass>(100);
(*mc)[10] = 3;
return mc;
}
void func(const MyClass& mc);
int main() {
auto mc = foo();
std::cout << (*mc)[10] << "\n"; // Can read individual values
//(*mc)[10] = 4; // Error const
func(*mc); // can pass to a function taking a const MyClass&
}
It's not possible. foo() has no way of knowing about the type of the left hand side of the assignment, because when the assignment itself happens, foo() is already evaluated. The best you could hope for is to change the return value, to try and cause a type-based error on the initialization:
#include <type_traits>
struct my_int {
const int m;
template<typename T, typename std::enable_if<std::is_const<T>::value, T>::type* = nullptr>
constexpr operator T() const {return m;}
};
constexpr my_int foo() { return {5};}
int main() {
const int a = foo();
int b = foo();
}
Live example
But this will also not work, because the typename in the template will never be substitued by a const-qualified type (in this specific case, it will be int for both lines in main()).
As the following is possible
const int x = 4;
int y = x;
the C++ language will not provide such a mechanism.
Remains making a int const by a macro mechanism.
#define int_const_foo(var) const int var = ___foo()
int_const_foo(a);
Drawback: foo cannot be hidden, and the syntax is no longer C style.
class c {
private:
int n[10];
public:
c();
~c();
int operator()(int i) { return n[i];};
};
class cc {
private:
public:
c *mass;
cc();
~cc();
c& operator*() const {return *mass;};
};
int somfunc() {
c *c1 = new c();
cc * cc1 = new cc();
(*cc1->mass)(1);
delete c1;
}
I've got a pointer into class cc to class c.
Is there any way to get rid of record like this:
(*cc1->mass)(1);
and write somethink like that:
cc1->mass(1);
is it impossible?
When I saw the tags "c++" and "operator overloading", my mind alarm turns ON.
C++ operator overloading is complex, and some operators like "()" or "->" make it more difficult.
I suggest, before overloading operators, making either a global function or method with the same purpouse, test it works, and later replace it with the operator.
Global friend function example:
class c {
private:
int n[10];
public:
c();
~c();
// int operator()(int i) { return n[i]; }
// there is a friend global function, that when receives a "c" object,
// as a parameter, or declares a "c" object, as a local variable,
// this function, will have access to the "public" members of "c" objects,
// the "thisref" will be removed, when turned into a method
friend int c_subscript(c thisref, int i) ;
};
int c_subscript(c* thisref, int i)
{
return c->n[i];
}
int main()
{
c* objC() = new c();
// do something with "objcC"
int x = c_subscript(objC, 3);
// do something with "x"
return 0;
} // int main(...)
Local function ( "method" ) example:
class c {
private:
int n[10];
public:
c();
~c();
// int operator()(int i) { return n[i]; }
int subscript(int i) ;
};
int c::subscript(int i)
{
return this.n[i];
}
int main()
{
c* objC() = new c();
// do something with "objcC"
int x = c->subscript(objC, 3);
// do something with "x"
return 0;
} // int main(...)
And, finally use the overloaded operator:
class c {
private:
int n[10];
public:
c();
~c();
int subscript(int i) ;
int operator()(int i) { return this.subscript(i); }
};
int c::subscript(int i)
{
return this.n[i];
}
int main()
{
c* objC() = new c();
// do something with "objcC"
int x = c->subscript(3);
// do something with "x"
int x = c(3);
// do something with "x"
return 0;
} // int main(...)
Note that in the final example, I keep the method with a unique identifier.
Cheers.
Could always do this:
class cc {
private:
c *_mass;
public:
c& mass() const {return *_mass;};
};
Now..
cc1->mass()(1);
If mass were an object, not a pointer, you could use the syntax you want:
class cc {
private:
public:
c mass;
cc();
~cc();
const c& operator*() const {return mass;};
};
…
cc1->mass(1);
You can with
(*(*cc1))(1)
because operator() is applied to an object, not a pointer.
You can use
(**cc1)(1);
Or
cc1->mass->operator()(1);