In a related question it's said that there's no such thing as a pointer to non-member const function. In addition, C++11 8.3.5/6 says
The effect of a cv-qualifier-seq in a function declarator is not the same as adding cv-qualification on top of the function type. In the latter case, the cv-qualifiers are ignored. [ Note: a function type that has a cv-qualifier-seq is not a cv-qualified type; there are no cv-qualified function types. —end note ]
If I understand it correctly, this means that there's no such thing as a non-member const function. (Although such functions are not const, they cannot be modified as per 3.10/6). In particular, pointers to const function are meaningless.
However, it seems that some compilers do create pointers to const function in type deduction contexts. For instance, consider the code:
#include <iostream>
void f() {}
template <typename T> void g( T*) { std::cout << "non const" << std::endl; }
template <typename T> void g(const T*) { std::cout << "const " << std::endl; }
int main() {
g(f);
}
When compiled with GCC and Intel the code outputs "non const" as I would expect from the quote above. However, the output is "const" when compiled with Clang and Visual Studio.
Is my interpretation correct?
Update:
Following the comments, I'm trying to clarify that I'm not talking about const member functions. I'm interested in non-member functions (but the same arguments probably apply to non-static member functions as well). I've also changed the question title to make it more precise.
Consistent with the resolution of g(f)
mentioned above, the line below is ilegal for GCC and Intel but not for Clang and Visual Studio
const auto* ptr = &f;
Update 2:
I agree with Andy Prowl's interpretation and have selected his answer. However, after that, I was made aware that this question is a CWG open issue.
By Alex Allain. The const keyword allows you to specify whether or not a variable is modifiable. You can use const to prevent modifications to variables and const pointers and const references prevent changing the data pointed to (or referenced).
Do not return non-const handles to Class data from const member Functions. From a language point of view, the pointer 'p' is part of the class and then cannot be modified in a 'const' function. But the pointed-to value is not part of the class, and may be modified.
The benefit of const correctness is that it prevents you from inadvertently modifying something you didn't expect would be modified.
Pointers can be declared as pointing to mutable (non-const) data or pointer to constant data. Pointers can be defined to point to a function. My coworkers and I were discussing the use of "const" with pointers and the question came up regarding the use of const with function pointers.
If I understand it correctly, this means that there's no such thing as a non-member const function. (Although such functions are not const, they cannot be modified as per 3.10/6). In particular, pointers to const function are meaningless.
Yes, there is no such a thing as a const
function, and attempts to create one are ignored, because of the very same Paragraph you quoted. This is important, because a program that anyhow creates a const
function type is not ill-formed (as was the case in C++03); simply, its attempt is disregarded, and a non-const
function type is considered instead.
This is probably what GCC and ICC fail to apply, because when the non-const
overload is removed, the program does not compile:
#include <iostream>
void f() {}
template <typename T> void g( T const*)
{
std::cout << "const " << std::endl;
}
int main() {
g(f); // ERROR with GCC and ICC, compiles with Clang
}
Concerning your interpretation:
When compiled with GCC and Intel the code outputs "non const" as I would expect from the quote above. However, the output is "const" when compiled with Clang and Visual Studio. Is my interpretation correct?
I don't believe so. As far as I can tell, Clang is right.
This conclusion is based on the fact that both function templates are viable, because const
qualifiers are ignored on function types, and one is more specialized than the other.
Per Paragraph 8.3.5/7 of the C++11 Standard, in fact:
[...] The effect of a cv-qualifier-seq in a function declarator is not the same as adding cv-qualification on top of the function type. In the latter case, the cv-qualifiers are ignored. [...]
This effectively makes the second function template viable for resolving the call (the first one obviously is). But since both function templates are viable, Paragraph 13.3.3.1 about overload resolution comes into play:
Given these definitions, a viable function F1 is defined to be a better function than another viable function F2 if for all arguments i, ICSi(F1) is not a worse conversion sequence than ICSi(F2), and then
— for some argument j, ICSj(F1) is a better conversion sequence than ICSj(F2), or, if not that,
— the context is an initialization by user-defined conversion (see 8.5, 13.3.1.5, and 13.3.1.6) and the standard conversion sequence from the return type of F1 to the destination type (i.e., the type of the entity being initialized) is a better conversion sequence than the standard conversion sequence from the return type of F2 to the destination type. [ ... ] or, if not that,
— F1 is a non-template function and F2 is a function template specialization, or, if not that,
— F1 and F2 are function template specializations, and the function template for F1 is more specialized than the template for F2 according to the partial ordering rules described in 14.5.6.2.
Since the second function template is more specialized than the first one, the second function template should be picked by overload resolution. Therefore, Clang is right.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With