Associative container to handle one element polymorphically - c++

Suppose I have the following setup:
#include <iostream>
#include <map>
using namespace std;
class A
{
public:
A() { val1 = 1;}
~A() { }
private:
int val1;
};
class B
{
public:
B() { val2 = 1;}
~B() { }
int getVal() {return val2;}
private:
int val2;
};
class C : public A, public B
{
int val3;
};
void fun(std::pair<int, B>& p) {
cout << "B val: " << p.second.getVal() << endl;
}
void fun2(B& b) {
cout << "B val: " << b.getVal() << endl;
}
int main(int argc, const char *argv[])
{
map<int, C> m;
m.insert(make_pair(1, C()));
m.insert(make_pair(2, C()));
//fun(*(m.begin())); // <---- Compilation error
fun2(m.at(1)); // Works correctly
return 0;
}
Code compiles successfully and works as expected when I make the call to fun2. However if I uncomment the line fun(*(m.begin()) I get the following compilation error:
a.cpp: In function ‘int main(int, const char**)’:
a.cpp:48:18: error: invalid initialization of reference of type ‘std::pair<int, B>&’ from expression of type ‘std::pair<const int, C>’
fun(*(m.begin()));
^
a.cpp:33:6: error: in passing argument 1 of ‘void fun(std::pair<int, B>&)’
void fun(std::pair<int, B>& p) {
Is there any way to make the compiler handle the second element of std::pair polymorphically?
P.S. Sorry if the title is misleading in any way. Couldn't find a better way of expressing this.

This:
*(m.begin())
evaluates to a nameless temporary object. To bind this to a reference, the reference must be const, so:
void fun(const std::pair<int, B>& p) {
and for that function to call getVal(), that must be const too:
int getVal() const {return val2;}

Related

passing const as this argument discards qualifiers [duplicate]

error: passing 'const A' as 'this' argument of 'void A::hi()' discards
qualifiers [-fpermissive]
I don't understand why I'm getting this error, I'm not returning anything just passing the reference of the object and that is it.
#include <iostream>
class A
{
public:
void hi()
{
std::cout << "hi." << std::endl;
}
};
class B
{
public:
void receive(const A& a) {
a.hi();
}
};
class C
{
public:
void receive(const A& a) {
B b;
b.receive(a);
}
};
int main(int argc, char ** argv)
{
A a;
C c;
c.receive(a);
return 0;
}
#edit
I fixed it using const correctness but now I'm trying to call methods inside of the same method and I get the same error, but the weird thing is that I'm not passing the reference to this method.
#include <iostream>
class A
{
public:
void sayhi() const
{
hello();
world();
}
void hello()
{
std::cout << "world" << std::endl;
}
void world()
{
std::cout << "world" << std::endl;
}
};
class B
{
public:
void receive(const A& a) {
a.sayhi();
}
};
class C
{
public:
void receive(const A& a) {
B b;
b.receive(a);
}
};
int main(int argc, char ** argv)
{
A a;
C c;
c.receive(a);
return 0;
}
error: passing 'const A' as 'this' argument of 'void A::hello()'
discards qualifiers [-fpermissive]
error: passing 'const A' as 'this' argument of 'void A::world()'
discards qualifiers [-fpermissive]
Your hi method is not declared as const inside your A class. Hence, the compiler cannot guarantee that calling a.hi() will not change your constant reference to a, thus it raises an error.
You can read more about constant member functions here and correct usage of the const keyword here.
// **const object can call only const member function()**
// **Modified Code**
#include <bits/stdc++.h>
using namespace std;
class A {
public:
void hi() const {
std::cout << "hi." << std::endl;
}
};
class B {
public:
void receive(const A& a) {
a.hi();
}
};
class C {
public:
void receive(const A& a) {
B b;
b.receive(a);
}
};
int main() {
ios_base::sync_with_stdio(false);
cin.tie(NULL);
#ifndef ONLINE_JUDGE
freopen("input.txt","r",stdin);
freopen("output.txt","w",stdout);
#endif
A a;
C c;
c.receive(a);
return 0;
}
As already mentioned, one option is to make hi method const-qualified.
Another option is to use const_cast at the time of calling the hi method like so
A& ref = const_cast <A&>(a);
ref.hi();

std::function incomplete type on const function

Consider the following code which works as expected:
#include <iostream>
#include <functional>
struct foo
{
std::function<int()> get;
};
struct bar
{
int get()
{
return 42;
}
};
int main()
{
foo f;
bar b;
f.get = std::bind(&bar::get, &b);
if (f.get())
std::cout << "f.get(): " << f.get() << std::endl;
return 0;
}
Now, let's assume that bar::get() is a const member function:
#include <iostream>
#include <functional>
struct foo
{
std::function<int()const> get;
};
struct bar
{
int get() const
{
return 42;
}
};
int main()
{
foo f;
bar b;
f.get = std::bind(&bar::get, &b);
if (f.get())
std::cout << "f.get(): " << f.get() << std::endl;
}
Using GCC 9.2, this snipped throws the following compiler error:
main.cpp:6:31: error: field 'get' has incomplete type 'std::function<int() const>'
6 | std::function<int()const> get;
| ^~~
In file included from /usr/local/include/c++/9.2.0/functional:59,
from main.cpp:2:
/usr/local/include/c++/9.2.0/bits/std_function.h:128:11: note: declaration of 'class std::function<int() const>'
128 | class function;
| ^~~~~~~~
I fail to understand why foo::get has incomplete type.
Could somebody point me towards the right direction for understanding this behavior and "fixing" it accordingly?
I have the need to bind a const member function to a function pointer.
int()const is an abominable type.
std::function<int()const> is not a type, because it doesn't match the only defined specialisation
namespace std {
template< class R, class... Args >
class function<R(Args...)> { ... };
}
Just use std::function<int()>.
The const bit only makes sense for member functions. You've already bound bar::get to an instance b to save it as a std::function.
As mentioned by #KamilCuk:
The constness is checked at std::bind, not at std::function
You don't need to pass explicit const to std::function. Just use your older prototype: std::function<int()>. It will work if you don't have const overload (that mean, you have either one of these int bar::get() or int bar::get() const) for the same member function (Otherwise, you need to type cast explicity).
Actually, your function (int bar::get() const) will be having a signature like this (behind the scenes):
// int bar::get() const
int get(const bar *const this)
{
return 42;
}
// int bar::get()
int get(bar *const this)
{
return 42;
}
If you have overloads and want to bind specific member function, you can do something like this:
typedef int(bar::*fptr)(void) const; // or remove const
std::bind((fptr)&bar::get, &b );
See this:
#include <iostream>
#include <functional>
#include <vector>
struct foo
{
std::function<int()> get;
};
struct bar
{
int get()
{
return 42;
}
int get() const
{
return 50;
}
};
int main()
{
foo f;
bar b;
typedef int (bar::*fptr)(void);
typedef int (bar::*fcptr)(void) const;
f.get = std::bind((fptr)&bar::get, &b);
if (f.get())
std::cout << "f.get(): " << f.get() << std::endl;
f.get = std::bind((fcptr)&bar::get, &b);
if (f.get())
std::cout << "f.get(): " << f.get() << std::endl;
}
Output:
f.get(): 42
f.get(): 50
std::bind does not pass through constness to the callable. Therefore, the following would work:
struct foo {
std::function<int()> get;
// ^ note there is no 'const'
};

Question about C++ call virtual function implemented in base from derived class

What is wrong with the following code?
struct A {
virtual int hash() const = 0;
virtual int hash(int x) const = 0;
};
struct B : public A {
int hash() const final {
return 10;
};
int hash(int x) const override {
return 10;
};
};
struct C : public B {
int hash(int x) const override {
return x;
}
};
#include <iostream>
int main() {
C a;
std::cout << a.hash() << std::endl;
std::cout << a.hash(20) << std::endl;
return 0;
}
I got compile error with the following error message
xx.cc:26:23: error: too few arguments to function call, single argument 'x' was
not specified
std::cout << a.hash() << std::endl;
~~~~~~ ^
xx.cc:17:3: note: 'hash' declared here
int hash(int x) const override {
^
1 error generated.
This is name hiding issue. According to the rule of name lookup,
(emphasis mine)
name lookup examines the scopes as described below, until it finds at least one declaration of any kind, at which time the lookup stops and no further scopes are examined.
So C::hash hides the name from the base class.
You can apply using to introduce the name into the class C scope.
struct C : public B {
using B::hash;
int hash(int x) const override {
return x;
}
};
Yeah, you have to redefine the overload within the derived class.
struct C : public B {
int hash(int x) const override {
return x;
}
int hash() const override {
return B::hash();
}
};
Or alternatively call via a reference to B
int main() {
C a;
B& b = a;
std::cout << b.hash() << std::endl;
std::cout << b.hash(20) << std::endl;
return 0;
}

std functional wrapper of const member function

#include <functional>
#include <iostream>
struct Foo {
Foo(int num) : num_(num) {}
void print_add(int i) const { std::cout << num_+i << '\n'; }
int get_num(int i) { return num_;}
void set_num(int i) { num_ = i;}
int num_;
};
int main() {
std::function<int(const Foo *, int)> f_get_num;
f_get_num = &Foo::get_num;
return 0;
}
This will generate a error, error: invalid conversion from ‘const Foo*’ to ‘Foo*’ [-fpermissive] at line f_get_num = &Foo::get_num. Foo::get_num type is int (Foo:: *fp)(int). Can anybody explain it? Thanks.
You cannot call non-const functions on const objects. You can pass const Foo* to f_get_num, but Foo::get_num takes non-const implicit this.
The following two calls are just as illegal:
Foo foo;
Foo const* const_ptr = &foo;
const_ptr->get_num(42);
f_get_num(const_ptr, 42); // results in const_ptr->get_num(42)
You can declare your get_num to be const:
int get_num(int i) const { return num_;}
And then your code will work correctly.
The other way is to make your f_get_num take non-const parameter, but that's not the way to go when your function is a getter and shouldn't modify the object.
std::function<int(Foo*, int)> f_get_num;
f_get_num = &Foo::get_num;

error: passing 'const …' as 'this' argument of '…' discards qualifiers

error: passing 'const A' as 'this' argument of 'void A::hi()' discards
qualifiers [-fpermissive]
I don't understand why I'm getting this error, I'm not returning anything just passing the reference of the object and that is it.
#include <iostream>
class A
{
public:
void hi()
{
std::cout << "hi." << std::endl;
}
};
class B
{
public:
void receive(const A& a) {
a.hi();
}
};
class C
{
public:
void receive(const A& a) {
B b;
b.receive(a);
}
};
int main(int argc, char ** argv)
{
A a;
C c;
c.receive(a);
return 0;
}
#edit
I fixed it using const correctness but now I'm trying to call methods inside of the same method and I get the same error, but the weird thing is that I'm not passing the reference to this method.
#include <iostream>
class A
{
public:
void sayhi() const
{
hello();
world();
}
void hello()
{
std::cout << "world" << std::endl;
}
void world()
{
std::cout << "world" << std::endl;
}
};
class B
{
public:
void receive(const A& a) {
a.sayhi();
}
};
class C
{
public:
void receive(const A& a) {
B b;
b.receive(a);
}
};
int main(int argc, char ** argv)
{
A a;
C c;
c.receive(a);
return 0;
}
error: passing 'const A' as 'this' argument of 'void A::hello()'
discards qualifiers [-fpermissive]
error: passing 'const A' as 'this' argument of 'void A::world()'
discards qualifiers [-fpermissive]
Your hi method is not declared as const inside your A class. Hence, the compiler cannot guarantee that calling a.hi() will not change your constant reference to a, thus it raises an error.
You can read more about constant member functions here and correct usage of the const keyword here.
// **const object can call only const member function()**
// **Modified Code**
#include <bits/stdc++.h>
using namespace std;
class A {
public:
void hi() const {
std::cout << "hi." << std::endl;
}
};
class B {
public:
void receive(const A& a) {
a.hi();
}
};
class C {
public:
void receive(const A& a) {
B b;
b.receive(a);
}
};
int main() {
ios_base::sync_with_stdio(false);
cin.tie(NULL);
#ifndef ONLINE_JUDGE
freopen("input.txt","r",stdin);
freopen("output.txt","w",stdout);
#endif
A a;
C c;
c.receive(a);
return 0;
}
As already mentioned, one option is to make hi method const-qualified.
Another option is to use const_cast at the time of calling the hi method like so
A& ref = const_cast <A&>(a);
ref.hi();