Given the code below:
class A
{
public:
A(): value( 0 ) {}
int* get()
{
return &value;
}
const int& get() const
{
return value;
}
private:
int value;
};
int main()
{
A a;
const int& ref_value = a.get();
}
results in the following compilation error:
prog.cpp: In function 'int main()':
prog.cpp:23:35: error: invalid conversion from 'int*' to 'int'
const int& ref_value = a.get();
^
It seems that the overloaded get() method with const modifier does get ignored completely and the compiler sees only the non-const definition of it. It is somehow understandable since the a object is not constant. One solution would be to make the a object constant. Though there are other two solutions that makes the code compileable:
Change the signature of the const get() method by different name or other parameters added.
int* get();
const int& get_changed() const; <-- this gets called
Change the non-const get() method to return a reference instead pointer.
int& get(); <-- this gets called
const int& get() const;
though with
int* get();
const int& get() const;
we have a compiler error.
What puzzles me is the reason behind all of these behavior.
When you have both a const and non-const overload of the same function with the same parameters, which one gets called depends only on the constness of the object on which you're invoking the function. So invoking on a non-const a must call the non-const overload.
It's exactly the same situation as this:
void foo(int *p);
void foo(const int *p);
int main()
{
int i;
const int ci;
foo(&i); // Calls the first overload
foo(&ci); // Calls the second overload
}
A const-qualified function can be called on a non-const-qualified object, but that requires a "nonconst to const" conversion. If there's an overload which doesn't require such a conversion (is a better match), it will be preferred.
The reason is that the compiler can't do overload resolution based on a different return type.
Only the function signature is taken into account for overload resolution. And the function signature consists only of the function name, the parameters, and the cv qualifiers - not the return type.
Related
Is there any difference between:
void (* const algorithm)();
and
void const (* const algorithm)();
when dealing with const pointers to static methods?
I understand that it would make sense to use const if the pointer points to memory that should not be modified, in case of pointers to variables, as stated in this answer. However, are function addresses not effectively constant during run-time anyway?
The reason I am asking this is, the second option as a function parameter does not work.
EDIT
Here is the code that does not compile.
struct A {
static void a() {}
};
void b(void const (* const callback)()) {}
int main() {
b(&A::a); // No matching function for call to 'b'
}
The above example works, if function a() has a return type const void.
const after (or before) the return type applies to the return type. There is no such thing as a "pointer to const function" as there is no such thing as a const function. (Although, there is such thing as a pointer to const member function, as const member functions do exist. But there the constness applies to the object argument, not to the function itself. There the constness is expressed in the same way as in the declaration of a member function - after the parenthesized parameter list).
There is no difference between void() and void const() in the sense that both functions behave exactly the same because there is no behavioral difference between a const void return type and a non-const void return type. Object cannot be const when there is no object.
I would expect a compiler to issue a warning when a non-class return value is directly qualified with const.
However, void() and void const() are different in the sense that void and void const are technically separate types, as are all const qualified types different from their non-const counterpart. Therefore the function pointers to const returning and non-const returning functions are different function pointer types. As such, the standard won't allow a function pointer to one type be bound to a function of another type.
So, to fix your non-compiling code, simply replace void const which is nonsensical with void in the function pointer.
Start with the "inner" const :
using void_function = void();
void (*p1)() = nullptr; // similar to `void_function* p1 = nullptr;`
void (* const p2)() = nullptr; // similar to `void_function* const p2 = nullptr;`
p2 is constant whereas p1 is mutable.
When moving const, as following:
const void_function* p3 = nullptr; // or void_function const* p3; // -> const has no effect
void (const* p4)() = nullptr; // Invalid syntax
There are no "const function" vs "mutable function".
Now, looking at function return type:
Types void () (function returning void) and const void () (function returning const void !?) are different.
Even if const void make no real sense, it is a valid type.
It might make sense to return const object from function to disallow "direct" modification of the object:
const std::string make_const_string();
make_const_string().push_back('*'); // Doesn't work
std::string s = make_const_string(); // OK, create mutable copy.
So to fix your code:
struct A {
static void a() {}
};
void b(void const (* const callback)()) {}
int main() {
b(&A::a); // No matching function for call to 'b'
}
You have to make &A::a match b's argument type:
static const void a() {}
void b(void (*const callback)())
I suggest second one as const void make no real sense.
I have a class B that has two methods, where one returns a pointer to a member variable and the other returns a const reference to the variable.
I try to call those methods. During the calls, I store the return values to respective return types.
I was expecting the appropriate return types would end up calling the appropriate methods, but I get a compilation error saying:
error: invalid conversion from ‘int*’ to ‘int’ [-fpermissive]
const int& refval2 = b.Get(); `
Here is my code:
#include <iostream>
class B{
public:
int* Get(){
return &x_;
}
const int & Get() const{
return x_;
}
private:
int x_ = 0;
};
int main(){
B b;
const int& refval2 = b.Get();
int* pval2 = b.Get();
}
Return type is not part of function signature, it's not considered in overload resolution.
In general, the candidate function whose parameters match the arguments most closely is the one that is called.
For non-static member function call, the type of the object to be called on involves too. There're two Get(), one is const and one is non-const. For b.Get();, the non-const Get() is an exact match; for the const Get() to be called the object b has to be converted to const. Then the non-const one wins, after that the compiler will try to convert the returned int* to const int& and fails.
So
B b;
int* pval2 = b.Get(); // call to non-const Get()
const B cb;
const int& refval2 = cb.Get(); // call to const Get()
Why is the int* Get() called insted of const int& Get()?
const int & Get() const
Is a const member function.
From class.this:
If the member function is declared const, the type of this is const X*
However, you declared:
B b;
as non-const which will call the non-const function int* Get(). Thus, the error.
There are two things
return type are not considered in overload resolution
Const ness of method is considered in over load resolution
If you remove const in second method, compiler will complain about ambiguity.
As already answered return type is not considered. So I see 3 possible solutions:
1 make it part of function signature:
class B {
public:
void Get( int *&refptr );
void Get( int &refval ) const;
};
int main(){
B b;
int refval2 = 0;
b.Get( refval2 );
int* pval2 = nullptr;
b.Get( pval2 );
}
but this produces pretty ugly code, so you better use method 2 or 3 -
2 use different function names, this is pretty obvious
3 use ignored parameter:
class B {
public:
int *Get( nullptr_t );
const int &Get() const;
};
int main(){
B b;
const int &refval2 = b.Get();
int* pval2 = b.Get( nullptr );
}
The problem is that the compiler thinks the two Get() functions are the same. If you create two identical functions with only varying return types, the compiler has no idea which function you want to use. To fix the problem, change the name of one or both of the Get() functions; say GetXPtr() and GetX().
It seems it is in VS2013. But why in effective c++' item 3, the non-const operator calls const operator when they do exactly the same thing?
This is the code in Effective c++ item 3:
class TextBlock {
public:
...
const char& operator[](std::size_t position) const // same as before
{
...
...
...
return text[position];
}
char& operator[](std::size_t position) // now just calls const op[]
{
return const_cast<char&>( // cast away const on type;
static_cast<const TextBlock&>(*this)[position] // add const to *this's type;call const version of op[]
);
}
...
};
A const object cannot use a non-const method. (Remember that operators are only methods).
But the converse is true: A non-const object can use a const method (although it will use a non-const equivalent if that's present).
A method is only const if it is marked as const: a compiler is not allowed to assert const-ness by inspecting the function body.
Yes: if a const member function is present, but no non-const version, then calling that function on a non-const object will use the const function.
#include <iostream>
struct Foo {
void bar() const { std::cout << "const bar()\n"; }
};
int main() {
Foo f;
f.bar();
}
prints const bar().
Note the reverse is not true. You may not call a non-const member function on a const object:
struct Foo {
void bar() { std::cout << "non-const bar()\n"; }
};
int main() {
const Foo f;
f.bar();
}
gives a compiler error:
SO.cpp: In function 'int main()':
SO.cpp:9:11: error: passing 'const Foo' as 'this' argument of 'void Foo::bar()' discards qualifiers [-fpermissive]
f.bar();
^
EC++ Item 3, Use const whenever possible has a subsection, Avoiding Duplication in const and Non-const Member Functions. The reason it suggests that you don't just let the compiler pick the const version is that the return types are different (by a const) - the non-const version casts this away:
class CharWrapper {
char c_;
public:
char const& getC() const
{
std::cout << "const getC()\n";
return c_; // pretend this line is complicated
}
char& getC()
{
std::cout << "non-const getC()\n";
char const& c = const_cast<CharWrapper const&>(*this).getC(); // call the right one to avoid duplicating the work
return const_cast<char&>(c); // fix the result type
}
};
int main() {
CharWrapper wrapper;
wrapper.getC() = 'a';
}
Notice that it calls const operator and casts away constness (it one of those few times where it does not result in UB). It is needed so non-const operator returns a mutable reference. Otherwise you would not be able to modify objects contained in vector at all.
Call to existing operator instead of writing code again is done to avoid code duplication and possible future errors when you change one function, but forgot the other.
Regarding your comment: there is no move involved. It returns a reference. I would expect no difference in generated code for both const and non-const operator.
I don't understand why this piece of code won't compile.
I get following error in line return source->GetA();
cannot convert 'this' pointer from 'const class FooStruct' to 'class
FooStruct &'
If I remove the const keyword it compiles fine.
class FooStruct
{
int a;
public:
int GetA() {return a;};
int Bar(const FooStruct *source);
};
int FooStruct::Bar(const FooStruct *source)
{
return source->GetA();
}
The code itself doesn't make sense. It has been stripped down from some real code and its only purpose is to illustrate the problem.
It is because of this line:
return source->GetA();
Here you are trying to execute GetA function on the pointer that you got. If the pointed object is const, the function must also be const, because:
Both const and non-const functions can be executed on non-const objects
Only const functions can be executed on const objects.
It is a good idea to mark all the functions that do not modify the state of the object as const, so they can be used on const objects (e.g. in functions that accept const T & as a parameter).
So in your case, the class should look like:
class FooStruct
{
public:
int GetA() const {return a;}
};
The function GetA itself needs to be marked const:
int GetA() const {
return a;
}
This then allows a const source* pointer to call that function.
whether it is possible to overload function by const specifier. That is, we have two functions, one constant the other is not, can we say that the constant function overloaded non-const function ?
Yes and No.
It depends on where you put the const specifier.
When defining member functions, this is possible (Yes-part):
int f() { /*code*/ } //invoke this function on non-const object
int f() const { /*code*/ } //ok : invoke this function on const object
Note that in the absence of the first function, even non-const object will invoke the second function (i.e const member function) and in the absence of the second function, you wouldn't be able to invoke the first function on const objects!
But this is not possible (No-part):
int g() { /*code*/ }
const int g() { /*code*/ } //error: redefinition
irrespective of whether they're member functions or free functions.
Per § 13.1 / 2:
It's not possible to put const in return-type to overload:
Function declarations that differ only in the return type cannot be
overloaded.
int func();
const int func(); // Error
It's not possible to put const in parameter-list to overload:
Parameter declarations that differ only in the presence or absence of
const and/or volatile are equivalent.
void func(int x);
void func(const int x); // Error
BUT, it's possible:
const and volatile type-specifiers buried within a parameter type
specification are significant and can be used to distinguish
overloaded function declarations.
void func(int &x);
void func(const int &x); // OK
And, it's possible to put const at end of method declaration to distinguish overloads:
int func();
int func() const; // OK