C++17 and "Alice in Wonderland"
I apologize for this non-Boost related post, but I ran into what I thought was a C++17 bug in clang ( also in vc++14.2 C++17 ), whose explanation to me of why it is not a bug really sounds like the non-logic of "Alice in Wonderland". I am not putting down the person who explains to me why it is not a bug in any way, as I know he is a C++ expert, but if this is really C++17 something must be wrong with my admittedly limited understanding of C++ and where it is going. My bug report is at https://bugs.llvm.org/show_bug.cgi?id=49684 and the explanation given there just eludes me as to what C++17 is doing, as my further comments makes apparent. Does anyone actually understand how this can possibly be ? How does C++17 apparently deduce a template argument different from what the actual type is and than declare therefore a mismatch ? This is really something from another world. My apologies for bringing this up in Boost, as it is purely a C++ issue, but my original problem comes from something I have been working on in the hopes it might eventually be a Boost library, so I decided to see if any of the expert Boost contributors might know what is going on in C++17. I realize that if everyone did as I have done here the mailing list would be a mass of irrelevant posts not Boost related.
On Tue, Mar 23, 2021 at 5:13 PM Edward Diener via Boost
I apologize for this non-Boost related post, but I ran into what I thought was a C++17 bug in clang ( also in vc++14.2 C++17 ), whose explanation to me of why it is not a bug really sounds like the non-logic of "Alice in Wonderland".
[snip]
My bug report is at https://bugs.llvm.org/show_bug.cgi?id=49684 and the explanation given there just eludes me as to what C++17 is doing,
[snip] Aren't consts ignored in function parameters? Then the parameter is not const and you have a mismatch. Can't you use different parameter types and use SFINAE by comparing the two after removing const? Kind regards, -- Felipe Magno de Almeida Owner @ Expertise Solutions www: https://expertise.dev phone: +55 48 9 9681.0157 LinkedIn: in/felipealmeida
On 3/24/2021 12:42 AM, Felipe Magno de Almeida via Boost wrote:
On Tue, Mar 23, 2021 at 5:13 PM Edward Diener via Boost
wrote: Hello Edward,
I apologize for this non-Boost related post, but I ran into what I thought was a C++17 bug in clang ( also in vc++14.2 C++17 ), whose explanation to me of why it is not a bug really sounds like the non-logic of "Alice in Wonderland".
[snip]
My bug report is at https://bugs.llvm.org/show_bug.cgi?id=49684 and the explanation given there just eludes me as to what C++17 is doing,
[snip]
Aren't consts ignored in function parameters?
Why are consts ignored in function parameters ? Is not void f(int const) different from void f(int) ? In one the argument passed can not be changed and in the other it can. How can they be the same ?
Then the parameter is not const and you have a mismatch. Can't you use different parameter types and use SFINAE by comparing the two after removing const?
Thanks ! Maybe I can. But to have to do so in such a simple situation seems very strange.
On 24.03.21 14:46, Edward Diener via Boost wrote:
Why are consts ignored in function parameters ? Is not void f(int const) different from void f(int) ? In one the argument passed can not be changed and in the other it can. How can they be the same ?
That's an implementation detail of the function f that doesn't (and shouldn't) affect the interface, and the type of f is part of its interface. Let's say that I write a function like this: void countdown(int start_val) { while (start_val >= 0) { std::cout << start_val << "\n" << std::flush; --start_val; } } Later I realize that changing the value of the start_val parameter is confusing, so I rewrite the function like this: void countdown(int const start_val) { for (int val = start_val; val >= 0; --val) { std::cout << val << "\n" << std::flush; } } I am (and should be) allowed to make this change without affecting any users of my function because it is purely an implementation change. -- Rainer Deyke (rainerd@eldwood.com)
On 2021-03-24 at 14:46, Edward Diener via Boost wrote:
On 3/24/2021 12:42 AM, Felipe Magno de Almeida via Boost wrote:
On Tue, Mar 23, 2021 at 5:13 PM Edward Diener via Boost
wrote: Hello Edward,
I apologize for this non-Boost related post, but I ran into what I thought was a C++17 bug in clang ( also in vc++14.2 C++17 ), whose explanation to me of why it is not a bug really sounds like the non-logic of "Alice in Wonderland".
[snip]
My bug report is at https://bugs.llvm.org/show_bug.cgi?id=49684 and the explanation given there just eludes me as to what C++17 is doing,
[snip]
Aren't consts ignored in function parameters?
Why are consts ignored in function parameters ? Is not void f(int const) different from void f(int) ? In one the argument passed can not be changed and in the other it can. How can they be the same ?
As a caller of the function, you cannot tell the difference. So why should they be different? :-)
On 2021-03-24 14:46, Edward Diener via Boost wrote:
Why are consts ignored in function parameters ? Is not void f(int const) different from void f(int) ? In one the argument passed can not be changed and in the other it can. How can they be the same ?
The standard states in [dcl.fct]/5 that "After producing the list of parameter types, any top-level cv-qualifiers modifying a parameter type are deleted when forming the function type."
Then the parameter is not const and you have a mismatch. Can't you use different parameter types and use SFINAE by comparing the two after removing const?
Thanks ! Maybe I can. But to have to do so in such a simple situation seems very strange.
You can use C++20 std::type_identity (or roll your own) to prevent the
second T from being deduced. In Richard Smith's example:
template
On 3/24/21 5:45 PM, Bjorn Reese via Boost wrote:
You can use C++20 std::type_identity (or roll your own) to prevent the second T from being deduced. In Richard Smith's example:
template
struct X; template struct X {}; X x;
As I commented in the clang bug, I don't think you should have to do this. There is only one T this template, and it is explicitly specified at the point of template instantiation, so there's nothing to deduce.
Am 23.03.2021 um 21:13 schrieb Edward Diener via Boost:
I apologize for this non-Boost related post, but I ran into what I thought was a C++17 bug in clang ( also in vc++14.2 C++17 )...
In a template of form
template
On 3/24/2021 4:41 AM, Daniela Engert via Boost wrote:
Am 23.03.2021 um 21:13 schrieb Edward Diener via Boost:
I apologize for this non-Boost related post, but I ran into what I thought was a C++17 bug in clang ( also in vc++14.2 C++17 )...
In a template of form
template
whatever up until C++14, the function argument type in the non-type template parameter was never looked at in the deduction of type T because NTTPs weren't deemed dependent on placeholder types in their function arguments. Beginning with C++17, they are. Therefore you may get conflicting type deduction because the second, additional deduction path from the function argument type in the NTTP will never deduce a top-level cv-qualified T in case of non-reference-like arguments. But the first, formerly only deduction path, may. And therein lies the conflict in your example where T = const char in the first path and T = char is in the second.
Well, at least this is my understanding of P0172.
I appreciate your explanation, and the following is not directed at you
personally:
What is there to deduce ? If I specify whatever
I also do not even begin to understand why 'bool (*)(char const)' becomes 'bool (*)(char)' in any logical world. Clearly a char const is not the same as a char. Who in their right minds would make up a rule that says they are the same, whether in a function declaration or not ? They clearly are not, unless you are out to destroy the notion that top-level consts in function declarations mean anything. That is pretty easy: The function type(!) does NOT include the const of value parameters. My goto for this is godbolt and an easy template test: https://godbolt.org/z/7MvbWb3EW This is why in the function declaration you can omit the const even when you use it in the definition and if you think about it it makes sense: If the function does or does not modify a copied (i.e. by-value) parameter doesn't matter to the caller at all.
Honestly if this is now C++, something seriously has gone wrong AFAICS. No doubt I am missing something basic, but this is truly "Alice in Wonderland" stuff to me. OK, I have had my rant. In what I was working on I will just specify that T as a top-level const is disallowed. My design can get by on that, rather than come up with some tortured code that allows T as a top-level const in the sort of signature above which works in both C++14 and C++17 on up.
In short the takeaway here is: Function value parameters in function signatures are never const.
Alexander Grund via Boost said: (by the date of Wed, 24 Mar 2021 14:49:51 +0100)
In short the takeaway here is: Function value parameters in function signatures are never const.
Just to make clear: value parameters are not reference parameters. const references are recognized. (the most useful argument types for a function :) Janek Kozicki
On 3/24/2021 4:41 AM, Daniela Engert via Boost wrote:
Am 23.03.2021 um 21:13 schrieb Edward Diener via Boost:
I apologize for this non-Boost related post, but I ran into what I thought was a C++17 bug in clang ( also in vc++14.2 C++17 )...
In a template of form
template
whatever up until C++14, the function argument type in the non-type template parameter was never looked at in the deduction of type T because NTTPs weren't deemed dependent on placeholder types in their function arguments. Beginning with C++17, they are. Therefore you may get conflicting type deduction because the second, additional deduction path from the function argument type in the NTTP will never deduce a top-level cv-qualified T in case of non-reference-like arguments. But the first, formerly only deduction path, may. And therein lies the conflict in your example where T = const char in the first path and T = char is in the second.
Well, at least this is my understanding of P0172.
I appreciate your explanation, and the following is not directed at you personally:
What is there to deduce ? The deduction comes from the NTTP, no matter if you provide a T for the first template argument. The type of the second template argument needs to be deduced. And since it is type-dependent on the function argument it implies a deduction of type T as well. This is the dichotomy between
Am 24.03.2021 um 14:38 schrieb Edward Diener via Boost: the old order and the new one.
If I specify whatever
then T is 'char const'. It's right there in my instantiation. Making it impossible in this simple situation to specify the T type when it is a top-level const type can not be C++ in any logical sense. I also do not even begin to understand why 'bool (*)(char const)' becomes 'bool (*)(char)' in any logical world. The declared type is 'bool (*)(char)' in both cases, cv-qualification isn't considered here. This semantic property of function parameters has meaning only within function block scope (or function parameter scope, too? I need to check). And therefore T is deduced to 'char'. Clearly a char const is not the same as a char. Who in their right minds would make up a rule that says they are the same, whether in a function declaration or not ? They clearly are not, unless you are out to destroy the notion that top-level consts in function declarations mean anything.
I think this rule exists since the inception of C++. Ciao Dani
Honestly if this is now C++, something seriously has gone wrong AFAICS. No doubt I am missing something basic, but this is truly "Alice in Wonderland" stuff to me. OK, I have had my rant. In what I was working on I will just specify that T as a top-level const is disallowed. My design can get by on that, rather than come up with some tortured code that allows T as a top-level const in the sort of signature above which works in both C++14 and C++17 on up.
_______________________________________________ Unsubscribe & other changes: http://lists.boost.org/mailman/listinfo.cgi/boost
-- PGP/GPG: 2CCB 3ECB 0954 5CD3 B0DB 6AA0 BA03 56A1 2C4638C5
participants (9)
-
Alexander Grund
-
Andrey Semashev
-
Bjorn Reese
-
Bo Persson
-
Daniela Engert
-
Edward Diener
-
Felipe Magno de Almeida
-
Janek Kozicki
-
Rainer Deyke