This question already has answers here:
Functions with const arguments and Overloading
(3 answers)
Closed 6 years ago.
Why does const create a different signature when its applied to a struct pointer as opposed to a struct?
E.g.
typedef struct test_s {
int foo;
} test;
void foo(test *ptr){
return;
}
// This is ok
void foo(const test *ptr){
return;
}
void foo(test t){
return;
}
//This is an error
void foo(const test t){
return;
}
(tested on gcc version 4.9.2)
To be more specific, why is it that the bottom one is an error when the pair with the pointers is not an error. The referenced duplicate question (Functions with const arguments and Overloading) would also seem to argue that the case with the pointers should be duplicates.
void foo(const test t){
return;
}
is an error since it is the same as:
void foo(test t){
return;
}
which makes it a duplicate of the previous function.
When the argument to a function is test*, you can dereference the pointer and modify it. The modification will be visible in the calling function.
void foo(test *ptr){
ptr->foo = 10; // The state of the object in the calling function
// is changed.
return;
}
When the argument to a function is const test*, you can dereference the pointer to access it but not modify it.
void foo(const test *ptr){
std::cout << ptr->foo << std::endl; // OK
ptr->foo = 10; // Not OK
return;
}
For the same reason, you can overload:
void foo(test& t);
void foo(const test& t);
When you try to overload
void foo(test t);
void foo(const test t);
Both are equally good candidates when you call it. The compiler cannot disambiguate between the two. In addition, take a look at one of the answers to the dupe. It cites the section of the C++ standard that states why the last two are equivalent.
Related
This question already has answers here:
What's a use case for overloading member functions on reference qualifiers?
(4 answers)
Closed 10 months ago.
I just discovered this is valid C++:
struct S {
int f() &; // !
int g() const &; // !!
};
int main() {
S s;
s.f();
s.g();
}
IIUC, this is passed to f by reference and to g be passed by const-reference.
How was this useful to anyone?
They are useful for both providing safety and optimizations.
For member functions returning a pointer to something they own (either directly or via view types like std::string_view or std::span), disabling the rvalue overloads can prevent errors:
struct foo {
int* take_ptr_bad() { return &x; }
int* take_ptr() & { return &x; }
int x;
};
foo get_foo();
void bar() {
auto ptr = get_foo().take_ptr_bad();
// ptr is dangling
auto ptr = get_foo().take_ptr();
// does not compile
}
The other is to provide some optimizations. For instance, you might overload a getter function to return an rvalue reference if this is an rvalue to prevent unnecessary copies:
struct foo {
const std::string& get_str() const & {
return s;
}
std::string&& get_str() && {
return std::move(s);
}
std::string s;
};
void sink(std::string);
foo get_foo();
void bar() {
sink(get_foo().get_str());
// moves the string only if the r-value overload is provided.
// otherwise a copy has to be made, even though the foo object
// and transitively the string is temporary.
}
These are how I use the feature, and I'm sure there are more use cases.
I'm trying to call const function inside a class, but a non-const function with the same name exists.
Note: I can't just change names.
class MyQuestion
{
void fun()
{
cout<<"a";
}
void fun()const
{
cout<<"b";
}
void call()
{
fun();//<how to call fun() const?
}
};
Option #1:
Call that function through a pointer to a const qualified type:
void call()
{
static_cast<const MyQuestion*>(this)->fun();
// ~~~~^
}
c++11:
void call()
{
const auto* that = this;
//~~^
that->fun();
}
c++17:
void call()
{
std::as_const(*this).fun();
// ~~~~~~~^
}
Option #2:
Make the calling function a const-qualified one:
void call() const
// ~~~~^
{
fun();
}
DEMO
You have to call the function on a const pointer. For this, I recommend to create a local pointer variable:
const auto *c = this;
c->fun(); // calls fun() const
fun(); // calls fun()
Live Demo
If you need that often, and/or if you don't want to use a local variable, you could also introduce a private helper function which returns a const this pointer:
const MyQuestion *const_this() const {
return this;
}
and then call fun like this:
const_this()->fun(); // calls fun() const
fun(); // calls fun()
Live Demo
Yet another option is to write a make_const function which performs a cast to a const pointer without the need to mention the class name (it's basically a static_cast to a const pointer of a deduced type):
template <typename T>
const T* make_const(T *ptr) {
return ptr;
}
and then call fun like this:
make_const(this)->fun(); // calls fun() const
fun(); // calls fun()
Live Demo
For the sake of argument (I don't recommend the following), combining with the suggestion above, you could also introduce a global macro which expands to make_const(this):
#define const_this make_const(this)
and then call fun like this:
const_this->fun(); // calls fun() const
fun(); // calls fun()
Live Demo
I would like to add another possible solution to the excelent ones already posted.
You can help the compiler to choose the correct overload using a function pointer with the expected signature:
// Pointer to the version of fun with const
void (MyQuestion::*f)()const = &MyQuestion::fun;
(this->*f)(); // This would call the const fun
See the demo here, or the full code below:
struct MyQuestion
{
void fun()
{
std::cout<<"a";
}
void fun()const
{
std::cout<<"b";
}
void call()
{
void (MyQuestion::*f)()const = &MyQuestion::fun;
(this->*f)();
}
};
Why does this work?
Well, the type of the f pointer is void (MyQuestion::*)()const which is the same of MyQuestion::foo()const but not the same of MyQuestion::foo(), so when you take te address of the function &MyQuestion::fun the pointer f could only point to the const version.
how about overloading call() itself. Following implementation does the job. I m guessing that it is what you want to implement.
#include <iostream>
using namespace std;
class A
{
public:
void fun() { cout << "non" << endl; }
void fun() const { cout << "const" << endl; }
void call() { fun(); }
void call() const { fun(); }
};
int main()
{
A a;
a.call();
const A b;
b.call();
return 0;
}
I have the following piece of c++11-code:
#include <iostream>
struct object {
void talk(const char* text) const { std::cout << "talk " << text << std::endl; }
};
void makeItTalk(object& obj) { obj.talk("non-const"); }
void makeItTalk(const object& obj) { obj.talk("const"); }
template<typename P> void f(P&& p) {
makeItTalk(std::forward<P>(p));
}
int main() {
const object obj;
f(obj);
return 0;
}
When running I get talk const which is what it should be, but I'm wondering how it works. From what I read so far the const-qualifier is ignored in template deduction. Since obj is of type const object& and we have a P&& as parameter in f I would expect that the template parameter resolves to object& and since & && = & the function f should become
void f(object& p) { makeItTalk(std::forward<object&>(p)); }
But this function is not even allowed to be called for obj. So I'm wondering if I am wrong by saying the const is ignored?
As I understand it, type deduction does not ignore the const qualifier when the function template takes a pointer or reference parameter. The top-level consts are removed but not the constness of what is pointed to or referenced.
A more extensive argument can be found here: http://cpp-next.com/archive/2011/04/appearing-and-disappearing-consts-in-c/
If I try to define a pointer to an overloaded function
void myprint(int );
void myprint(const char* );
void (*funpointer)(int) = myprint;
the compiler understands that funpointer should point to the version of myprint that matches its arguments. Instead, I want funpointer to be overloaded as well.
I tried simply adding a couple lines like
void myprint(int );
void myprint(const char* );
void (*funpointer)(int);
void (*funpointer)(const char *);
void funpointer = myprint;
but then the compiler complains of conflicting declarations for funpointer (obviously).
Is there a way to achieve what I'm looking for? I would like the pointer to behave as an overloaded function. So I could call it as either funpointer(1) or funpointer("Hey.") and it would work as the respective version of myprint.
Why are you doing this? Function pointers are for runtime polymorphism based on application state. Plain old overloads work fine if, the only variance is the argument type.
If you want to be able to, say write a library that will call overloads defined later, in client code, do something like the following:
void foo(int x) { printf("int\n");}
void foo(const char* c){ printf("char*\n"); }
template <class T> void callfoo(T t) { foo(t); }
int main(int argc, char* argv[])
{
int x = 3;
callfoo(x);
const char* p = "Hello world";
callfoo(p);
return 0;
}
This allows the lib to call overloads for types it is not actually aware of until link time.
No can do. You can't have two variables in the same scope with the same name.
Pointer is a Type, it cannot be overloaded. Only functions can be overloaded.
There is no way to achieve overloading of a pointer in C++.
You can't do it with function pointers... the argument list is part of the type, so any given function pointer can only correspond to one specific overload at a time. You might be able to fake it with function objects, though, depending on what you need to do.
struct MyPrint {
void operator()(int i) { int_f(i); }
void operator()(const char* c_str) { str_f(c_str); }
std::function<void(int)> int_f;
std::function<void(const char*) str_f;
};
void print_int(int i) { cout << i << endl; }
void print_string(const char* str) { cout << str << endl; }
int main() {
MyPrint p;
p.int_f = print_int;
p.str_f = print_string;
p(5);
p("Hi");
}
You lose the ability to just overload by name; you can't add a set_functions(f) that takes a function name and extracts both versions of the function. But as I showed, now you aren't limited to functions with the same name, or even just to functions. The object is also bigger than it used to be, and likely involves some heap allocations.
This might be considered "clunky", but you could do something like the following:
template<typename T>
struct funcptr_struct
{
typedef T type;
static type ptr;
};
template<> funcptr_struct<void(*)(int)>::type funcptr_struct<void(*)(int)>::ptr = myprint;
template<> funcptr_struct<void(*)(const char*)>::type funcptr_struct<void(*)(const char*)>::ptr = myprint;
You can then call each version of the myprint function using syntax like the following:
funcptr_struct<void(*)(int)>::ptr(5);
This question already has answers here:
Overload resolution with std::function
(2 answers)
Closed 6 years ago.
consider some code:
void foo() { }
bool bar() { return true; }
struct S
{
void operator=(std::function<void()> f){f();};
void operator=(std::function<bool()> f){f();};
};
int main() {
S s;
s = foo; // ok
s = bar; // error: use of overloaded operator '=' is ambiguous
}
How can I make this example unambiguous?
The problem you're running into is that std::function<void(Args...)> is allowed to discard return types - so both std::function<void()> and std::function<bool()> can be constructed from a bool(*)(). The latter will forward through the return from bar, but the former will just discard it. That's perfectly valid behavior, but causes this to be ambiguous.
What you probably want is to avoid std::function altogether:
template <class F>
void operator=(F f) { f(); }