Why does C ++ allow but ignore the application of const types to functions?

I get a real kick from exploring unusual C ++ angles. Having learned about the real types of functions, and not about function pointers from this question , I tried to mess around with the typing function and came up with this strange case:

typedef int Func(int); int Foo(int x) { return 1; } int main() { const Func*& f = &Foo; return 0; } 

Since &Foo is an rvalue of type Func* , I decided that I should be able to put it in a const link, but I get this error from g ++ 4.6:

 funcTypes.cpp: In function 'int main()': funcTypes.cpp:7:23: error: invalid initialization of non-const reference of type 'int (*&)(int)' from an rvalue of type 'int (*)(int)' 

But f is const! It became obvious to me that the application of const to a function (or link / link to a pointer, etc.) is simply ignored; this code compiles just fine:

 template <typename A, typename B> struct SameType; template <typename A> struct SameType<A, A> { }; typedef int Func(int); int main() { SameType<const Func, Func>(); return 0; } 

I suppose this speeds up the removal of their is_function , but my question is: why does C ++ allow this by ignoring it and not banning it?

EDIT: Now I understand that in the first example, f not const and that const FuncPtr& f = &Foo works. However, it was just the background, the real question is the one above.

+6
source share
6 answers

But f is const!

No no. You confuse

 const Func*& f = &Foo; 

from

 Func* const& f = &Foo; 

The first is a non-const ref for the const pointer. The latter is the ref constant for the non-constant pointer.

That's why I always write a constant before * / & and not before a type. I would always record the first case as

 Func const*& f = &Foo; 

and then read from right to left: a link to a pointer to a Func constant.

+4
source

In C ++ 03, it was not ignored, but unformalized (and there was a case of sfinae). I assume they changed this in C ++ 11, because then you can just have the functional parameters const F& and pass objects to the rvalue function, as well as regular functions.

See this DR that made the changes http://www.open-std.org/jtc1/sc22/wg21/docs/cwg_defects.html#295

+3
source

&Foo is a pointer. In general, I would suggest avoiding references to pointers ( const or no). At least if you do not know what you are doing.

So you should have:

 const Func *f = &Foo; 

Or, indeed, you can completely disable const :

 Func *f = &Foo; 

why does C ++ allow this by ignoring it and not banning it?

Because you are talking about two different things.

In C ++, there is a difference between a function type and a function pointer. Foo is a type of function, in particular int(int) . &Foo is a pointer to a function of type int(*)(int) . The type of a function degrades to a function pointer where necessary (similar to how array types degrade to pointers). But they are different (like arrays).

So your two cases do not match. Your first case deals with a function pointer, and your second case deals with a function type (which is what the template argument is output as).

As for why function types swallow const , this is because the values ​​of function types are already implicitly constant. You cannot change them. The only operation you can perform on a function type is () (or conversion to a function pointer). Thus, const T equivalent to T if T is a type of function. Visual Studio 2010 really gives a warning about this.

+2
source

The following compiled files:

 typedef int Func(int); int Foo(int x) { return 1; } int main() { Func* const& f = &Foo; //ok return 0; } 

Remember that const statements are evaluated along with pointers and references from right to left. The last constant to your left translates into the last possible position to the right of your name ( C ++ FAQ on placing constants ). Consequently,

 const Func*& f 

Translated by the compiler to

 Func const*& f 

Therefore, you get a link to a constant pointer, which is not what you want. In addition, I would not use references to a function pointer unless you really need it.

+1
source

No, f not const. First of all, this is a reference to some kind of mutable type (this mutable type is a const pointer, i.e. a mutable pointer that you promise not to change through this particular pointer). However, with &Foo you create a temporary (such as Func* ), and you cannot assign a temporary reference to a variable. You can assign it only for const reference. And this is exactly what the error message reports.

0
source

Sometimes error messages can be a little cryptic.

I gave an ideone example to illustrate the types printed by gcc for different things:

 #include <iostream> typedef int(Func)(int); typedef Func* FuncPtr; typedef FuncPtr& FuncPtrRef; typedef FuncPtr const& FuncPtrConstRef; template <typename T> void DisplayType() { T::foo(); } int main() { DisplayType<Func>(); DisplayType<FuncPtr>(); DisplayType<FuncPtrRef>(); DisplayType<FuncPtrConstRef>(); } 

Compilation errors give:

  • Func is of type int ()(int) (not a valid type, should now be fixed in gcc)
  • FuncPtr is of type int (*)(int)
  • FuncPtrRef is of type int (*&)(int)
  • FuncPtrConstRef is of type int (* const&)(int)

In the error message, you have int (*&)(int) , which is a reference to a non-constant pointer to the type of the function.

You are not allowed to bind the value of r to a non-constant reference.

Note: at the same time, const not swallowed, since smparkes is correctly diagnosed

0
source

Source: https://habr.com/ru/post/903271/


All Articles