Google Groups no longer supports new Usenet posts or subscriptions. Historical content remains viewable.
Dismiss

bool foo = [](){};

63 views
Skip to first unread message

Vir Campestris

unread,
Apr 11, 2019, 4:27:52 PM4/11/19
to
Spot the deliberate mistake?

The real code was more like

bool foo = [](){
/* various bits of logic */
return false;
};

It should have been

bool foo = [](){
/* various bits of logic */
return false;
}();

All my test cases wanted true, and that's what I got :( it was someone
else on different H/W that needed false.

Why is it possible to cast a lambda to a bool? And why doesn't GCC think
this is worth a warning, even on -pedantic?

</rant>
Andy

Sam

unread,
Apr 11, 2019, 8:53:15 PM4/11/19
to
Try making the lambda capture something. A capture-less lambda is equivalent
to a plain function pointer, and a pointer (expr) in boolean context is
equivalent to (expr) != null;


David Brown

unread,
Apr 12, 2019, 3:15:23 AM4/12/19
to
It does not get a warning because it is legal code - the lambda is much
like a function pointer and the bool is set to true to show the lambda
is a valid function pointer. "-pedantic" does not enable any warnings
about legal but questionable code - it merely makes the compiler
stricter about sticking to the standard and avoiding extensions.

Put "-Wall" in your command line, and gcc will happily warn you.


Juha Nieminen

unread,
Apr 12, 2019, 3:41:09 AM4/12/19
to
Vir Campestris <vir.cam...@invalid.invalid> wrote:
> Spot the deliberate mistake?
>
> The real code was more like
>
> bool foo = [](){
> /* various bits of logic */
> return false;
> };

Any pointer can be implicitly cast to bool. A null pointer will
evaluate to false and a non-null pointer will evaluate to true.
This includes function pointers, and your lamdba there implicitly
converts to a (non-null) function pointer (because it doesn't
capture anything), and therefore evaluates to true when assigned to
a bool.

Pointers implicitly casting to bool is inherited from C. Whether
that's a good or bad thing is up to opinion.

Alf P. Steinbach

unread,
Apr 12, 2019, 5:32:35 AM4/12/19
to
On 12.04.2019 09:41, Juha Nieminen wrote:
> Vir Campestris <vir.cam...@invalid.invalid> wrote:
>> Spot the deliberate mistake?
>>
>> The real code was more like
>>
>> bool foo = [](){
>> /* various bits of logic */
>> return false;
>> };
>
> Any pointer can be implicitly cast to bool. A null pointer will
> evaluate to false and a non-null pointer will evaluate to true.
> This includes function pointers, and your lamdba there implicitly
> converts to a (non-null) function pointer (because it doesn't
> capture anything), and therefore evaluates to true when assigned to
> a bool.

Yes, IMO that's a good & comprehensive explanation.


> Pointers implicitly casting to bool is inherited from C. Whether
> that's a good or bad thing is up to opinion.

But here I disagree. Technically it's up to one's opinion. But I fail to
see any advantage of the implicit conversion to `bool` in modern
programming.

An explicit cast like `!!p` (which used to also help with inane
sillywarnings about performance from the Visual C++ compiler) is more
clear and not significantly more to write, and avoids all the implicit
conversion problems that Andy's code is one example of.

Maybe one should therefore start using a type like, off the cuff,

class Strict_bool
{
bool m_value;

public:
explicit operator bool() const { return m_value; }

template<
class T,
class = enable_if< same_type_v<T, bool> >
>
Strict_bool( const T value ): m_value( value ) {}
};

I think to avoid clashes with numerous existing types called `Bool`, and
to reduce verbosity, I'd call it `Truth`.

Then one could talk about "Truth values". :)


Cheers!,

- Alf

Alf P. Steinbach

unread,
Apr 12, 2019, 9:54:57 AM4/12/19
to
On 12.04.2019 11:32, Alf P. Steinbach wrote:
> [snip]
> Maybe one should therefore start using a type like, off the cuff,
>
>     class Strict_bool
>     {
>         bool m_value;
>
>     public:
>         explicit operator bool() const { return m_value; }
>
>         template<
>             class T,
>             class = enable_if< same_type_v<T, bool> >
>             >
>         Strict_bool( const T value ): m_value( value ) {}
>     };
>
> I think to avoid clashes with numerous existing types called `Bool`, and
> to reduce verbosity, I'd call it `Truth`.
>
> Then one could talk about "Truth values". :)

Trying out that idea, I ended up with the following:


<url:
https://github.com/alf-p-steinbach/cppx-core/blob/master/source/cppx-core/language/types/Truth.hpp>
--------------------------------------------------------------------------------
#pragma once // Source encoding: UTF-8 with BOM (π is a lowercase
Greek "pi").
//
// A boolean type without implicit conversion from integral or pointer
types.

#include <cppx-core/language/tmp/basic-Enable_if_.hpp> //
cppx::Enable_if_
#include <cppx-core/language/syntax/macro-use.hpp> // CPPX_USE_STD

#include <type_traits> // std::is_same_v

namespace cppx
{
CPPX_USE_STD( is_same_v );

class Truth
{
bool m_value;

public:
constexpr operator bool() const { return m_value; }

template<
class Arg,
class = Enable_if_<is_same_v<Arg, bool>>
>
constexpr Truth( const Arg value ): m_value( value ) {}
};
} // namespace cppx

--------------------------------------------------------------------------------

I discovered that as of C++17 it can't be used for template value
parameters.

However, also that will possibly become supported in C++20. :)


Cheers!,

- Alf

Mr Flibble

unread,
Apr 12, 2019, 11:19:40 AM4/12/19
to
Why are you doing this? We already have "explicit" ctor and conversion
operator:

constexpr explicit operator bool() const noexcept;

/Flibble

--
“You won’t burn in hell. But be nice anyway.” – Ricky Gervais

“I see Atheists are fighting and killing each other again, over who
doesn’t believe in any God the most. Oh, no..wait.. that never happens.” –
Ricky Gervais

"Suppose it's all true, and you walk up to the pearly gates, and are
confronted by God," Bryne asked on his show The Meaning of Life. "What
will Stephen Fry say to him, her, or it?"
"I'd say, bone cancer in children? What's that about?" Fry replied.
"How dare you? How dare you create a world to which there is such misery
that is not our fault. It's not right, it's utterly, utterly evil."
"Why should I respect a capricious, mean-minded, stupid God who creates a
world that is so full of injustice and pain. That's what I would say."

Alf P. Steinbach

unread,
Apr 12, 2019, 11:37:35 AM4/12/19
to
It turned out, when I declared various compile time constants as `Truth`
instead of former `bool`, that with the `explicit` conversion to `bool`
they couldn't be used directly as template parameter arguments.

That's not a problem with e.g. `if` conditions, where the standard has a
wording that makes `explicit` conversion to `bool` implicit. :-o :)

I just didn't think of templates when I wrote the off-the-cuff 1st version.

It's not so big a deal to add `!!` in front, but on the other hand that
puts the burden of providing the conversion on each and every such use
of the class, instead of the class doing it in a single place.

So I changed to implicit conversion, so a `Truth` value can be used
directly as template parameter argument.

And to tackle the overload resolution issues that that in itself
introduces I added a SFINAE restriction (not shown above, but it's on
GitHub) so that it doesn't convert to anything other than `bool`.


Cheers!,

- Alf

Alf P. Steinbach

unread,
Apr 12, 2019, 11:39:37 AM4/12/19
to
On 12.04.2019 17:19, Mr Flibble wrote:
>
> constexpr explicit operator bool() const noexcept;

Thanks, I forgot the `noexcept`, will add.


Cheers!,

- Alf


blt_ng...@0uwnnh_23vzpr.org

unread,
Apr 12, 2019, 11:49:02 AM4/12/19
to
On Fri, 12 Apr 2019 17:39:28 +0200
"Alf P. Steinbach" <alf.p.stein...@gmail.com> wrote:
>On 12.04.2019 17:19, Mr Flibble wrote:
>>
>> constexpr explicit operator bool() const noexcept;
>
>Thanks, I forgot the `noexcept`, will add.

Why not throw in a final too. If you're going for unreadable syntatic soup you
might as well use as many ingredients as possible.

Alf P. Steinbach

unread,
Apr 12, 2019, 11:54:35 AM4/12/19
to
<plink>

Mr Flibble

unread,
Apr 12, 2019, 12:15:55 PM4/12/19
to
Good luck with that <plink>, the poster appears to be using randomly
generated e-mail addresses.

Ben Bacarisse

unread,
Apr 12, 2019, 12:40:31 PM4/12/19
to
"Alf P. Steinbach" <alf.p.stein...@gmail.com> writes:

> On 12.04.2019 09:41, Juha Nieminen wrote:
<cut>
>> Pointers implicitly casting to bool is inherited from C. Whether
>> that's a good or bad thing is up to opinion.
>
> But here I disagree. Technically it's up to one's opinion. But I fail
> to see any advantage of the implicit conversion to `bool` in modern
> programming.
>
> An explicit cast like `!!p` (which used to also help with inane
> sillywarnings about performance from the Visual C++ compiler) is more
> clear and not significantly more to write, and avoids all the implicit
> conversion problems that Andy's code is one example of.

It doesn't avoid it -- it relies on it. Both the initialisation of a
bool from a pointer, and the application of ! to a pointer, use the
standard conversions, which is what you and Juha (and almost everyone!)
calls implicit conversions.

Of course C++ could be changed to remove this standard pointer to bool
conversion and to add a special rule about pointer operands of !, but
that's not how things stand at the moment.

--
Ben.

Alf P. Steinbach

unread,
Apr 12, 2019, 1:12:30 PM4/12/19
to
On 12.04.2019 18:40, Ben Bacarisse wrote:
> "Alf P. Steinbach" <alf.p.stein...@gmail.com> writes:
>
>> On 12.04.2019 09:41, Juha Nieminen wrote:
> <cut>
>>> Pointers implicitly casting to bool is inherited from C. Whether
>>> that's a good or bad thing is up to opinion.
>>
>> But here I disagree. Technically it's up to one's opinion. But I fail
>> to see any advantage of the implicit conversion to `bool` in modern
>> programming.
>>
>> An explicit cast like `!!p` (which used to also help with inane
>> sillywarnings about performance from the Visual C++ compiler) is more
>> clear and not significantly more to write, and avoids all the implicit
>> conversion problems that Andy's code is one example of.
>
> It doesn't avoid it -- it relies on it.

In the language that we have, yes.


> Both the initialisation of a
> bool from a pointer, and the application of ! to a pointer, use the
> standard conversions,

Yes, but that's pretty irrelevant. Nobody's contested that or failed to
understand it. Assuming that Andy posted his question more as a possibly
interesting teaser that he fully knew the answer to, than as a way to
learn what was going on.


> which is what you and Juha (and almost everyone!)
> calls implicit conversions.

“Implicit conversion” is a description, a descriptive term; there is no
need to be pedantic about it. In fact the formal term “standard
conversion” is more limited, namely an implicit conversion with built-in
meaning (see C++17 §7/1). As I understand it formal “standard
conversion” does therefore /not/ cover use of a non-`explicit`
conversion operator, which is a case that both formal and informal
“implicit conversion” do cover.

Summing up, pedantry has its costs, so use with care. ;-)


> Of course C++ could be changed to remove this standard pointer to bool
> conversion and to add a special rule about pointer operands of !, but
> that's not how things stand at the moment.

Yes.

Which is why I suggested a `Strict_bool` class in the immediately
following text, a clarifying supportive context and what the earlier
remarks led up to, that you snipped.

The current version of that class, called `Truth`, is available at <url:
https://github.com/alf-p-steinbach/cppx-core/blob/master/source/cppx-core/language/types/Truth.hpp>.

It's mostly a drop-in replacement for `bool`, avoiding the undesired
implicit conversions.

As of C++17 there is one usage where `bool` can't be replaced with
`Truth` or a similar class, namely as a template value parameter. As I
understand it that situation will change with C++20. However, template
value parameters only introduce limited scope for conversion problems.


Cheers & hth.,

- Alf

Alf P. Steinbach

unread,
Apr 12, 2019, 1:16:26 PM4/12/19
to
I didn't realize it but this kind of class solves the
sometimes-a-problem with the specialization of `std::vector<bool>`,
where indexing returns a proxy rather than a raw reference.

Cheers!,

- Alf


Ben Bacarisse

unread,
Apr 12, 2019, 2:48:24 PM4/12/19
to
"Alf P. Steinbach" <alf.p.stein...@gmail.com> writes:

> On 12.04.2019 18:40, Ben Bacarisse wrote:
>> "Alf P. Steinbach" <alf.p.stein...@gmail.com> writes:
>>
>>> On 12.04.2019 09:41, Juha Nieminen wrote:
>> <cut>
>>>> Pointers implicitly casting to bool is inherited from C. Whether
>>>> that's a good or bad thing is up to opinion.
>>>
>>> But here I disagree. Technically it's up to one's opinion. But I fail
>>> to see any advantage of the implicit conversion to `bool` in modern
>>> programming.
>>>
>>> An explicit cast like `!!p` (which used to also help with inane
>>> sillywarnings about performance from the Visual C++ compiler) is more
>>> clear and not significantly more to write, and avoids all the implicit
>>> conversion problems that Andy's code is one example of.
>>
>> It doesn't avoid it -- it relies on it.
>
> In the language that we have, yes.
>
>> Both the initialisation of a
>> bool from a pointer, and the application of ! to a pointer, use the
>> standard conversions,
>
> Yes, but that's pretty irrelevant. Nobody's contested that or failed
> to understand it.

Ah, that was not clear (at least to me). I thought you objected to the
implicit conversion and were suggesting !! to avoid it. What is it that
using !! avoids?

>> which is what you and Juha (and almost everyone!)
>> calls implicit conversions.
>
> “Implicit conversion” is a description, a descriptive term; there is
> no need to be pedantic about it.

Sorry, I did not intend to be pedantic -- that's why I said almost
everyone uses that term (I certainly do). It just happens that I'd seen
the term the standard uses, so I though it best to use the official one.

> In fact the formal term “standard conversion” is more limited, namely
> an implicit conversion with built-in meaning (see C++17 §7/1). As I
> understand it formal “standard conversion” does therefore /not/ cover
> use of a non-`explicit` conversion operator, which is a case that both
> formal and informal “implicit conversion” do cover.
>
> Summing up, pedantry has its costs, so use with care. ;-)

I wasn't being pedantic (at least not intentionally). Obviously
"standard conversion" is a more limited term, but are you saying it's
the wrong one to use here? I am very much /not/ a C++ expert, so I may
not have navigated the maze of initialisation possibilities correctly.

--
Ben.

Alf P. Steinbach

unread,
Apr 12, 2019, 3:07:08 PM4/12/19
to
Sorry, I was possibly/likely committing the novice error of assuming
telepathic readers.

In my defense, I just successfully yesterday fought the first current
kidney stone, by the help of a transfusion of half a litre of water
directly into the blood so helping me fill bladder enough to be able to
u***ate that bastard out. But the CT scans say there's a brother
lurking. And some other physical problems turned up today, so I was not
my ordinary good (or mediocre) self, and I'm still not; again, sorry.

In my head I was thinking of language design alternatives to the
implicit conversions, which would not necessitate anything but the
already existing machinery such as the `!` operator.

[snip]

Cheers!,

- Alf

Vir Campestris

unread,
Apr 12, 2019, 4:35:00 PM4/12/19
to
On 12/04/2019 08:15, David Brown wrote:
> Put "-Wall" in your command line, and gcc will happily warn you.

Not when I tried it. Though I didn't try Gcc8.

Andy

Ben Bacarisse

unread,
Apr 12, 2019, 4:35:51 PM4/12/19
to
We all do that. Every post has to assume some background knowledge and
context.

> In my defense, I just successfully yesterday fought the first current
> kidney stone, by the help of a transfusion of half a litre of water
> directly into the blood so helping me fill bladder enough to be able
> to u***ate that bastard out. But the CT scans say there's a brother
> lurking. And some other physical problems turned up today, so I was
> not my ordinary good (or mediocre) self, and I'm still not; again,
> sorry.

Sorry to hear that. It sounds awful. I hope things get better for you
really soon.

> In my head I was thinking of language design alternatives to the
> implicit conversions, which would not necessitate anything but the
> already existing machinery such as the `!` operator.

Ah, I see.

--
Ben.

Vir Campestris

unread,
Apr 12, 2019, 5:02:25 PM4/12/19
to
On 12/04/2019 18:12, Alf P. Steinbach wrote:
> Yes, but that's pretty irrelevant. Nobody's contested that or failed to
> understand it. Assuming that Andy posted his question more as a possibly
> interesting teaser that he fully knew the answer to, than as a way to
> learn what was going on.

It was a teaser. Except for why the compiler doesn't think it worth
mentioning that the 20 lines of code that follows can never be executed.

Just like if you type

if([](){})

it's precisely and exactly equivalent to if(true). Except as an entry in
the obfuscated C++ contest...

BTW you might like to look at lithotripsy. And drink more!

Andy

Paavo Helde

unread,
Apr 13, 2019, 3:32:49 AM4/13/19
to
Interestingly enough, MSVC 2017 refuses to compile your original code.
Probably a bug in MSVC:

#include <iostream>
int main() {
bool foo = []() {
std::cout << "various bits of logic\n";
return false;
};
return foo ? 0 : 1;
}

1>d:\test\consoletestvs2017\consoletestvs2017\main.cpp(6): error C2440:
'initializing': cannot convert from
'main::<lambda_5ef23b46cf9064836fd2b269f298ffd7>' to 'bool'
1>d:\test\consoletestvs2017\consoletestvs2017\main.cpp(6): note:
Ambiguous user-defined-conversion




Melzzzzz

unread,
Apr 13, 2019, 4:06:21 AM4/13/19
to
What user defined conversion?
>
>
>
>


--
press any key to continue or any other to quit...

Paavo Helde

unread,
Apr 13, 2019, 5:22:31 AM4/13/19
to
No idea, the example is verbatim.


David Brown

unread,
Apr 13, 2019, 7:48:38 AM4/13/19
to
I tested it with godbolt.org, using gcc "trunk". I haven't tried other
versions, so it could well be a relatively new warning. godbolt.org
will make it easy for you to establish which gcc (or clang, or MSVC)
version you might find useful here.

Manfred

unread,
Apr 13, 2019, 9:11:38 AM4/13/19
to
gcc 8.2.1 issues a warning (about the function pointer never being NULL)
with -std=c++17 and -Wall
It will is silent with -std=c++{14,11} regardless of -Wall

Alf P. Steinbach

unread,
Apr 13, 2019, 9:55:02 AM4/13/19
to
On 13.04.2019 11:22, Paavo Helde wrote:
>
> #include <iostream>
> int main() {
>     bool foo = []() {
>         std::cout << "various bits of logic\n";
>         return false;
>     };
>     return foo ? 0 : 1;
> }

I believe that Visual C++ 2013 supported a number of raw function
signatures, e.g.

auto() -> bool
auto __cdecl () -> bool
auto __stdcall () -> bool
auto __fastcall () -> bool
auto __vectorcall () -> bool

... and that it internally provided this conversion via /as if/ type
conversion operator overloads.

Assuming those overloads are still in place under the hood, in some
form, that could explain the claimed ambiguity.

However, Visual C++2019 appears to give preference/priority to the
undecorated default variant. At least, if you place a `+` in front of
the lambda it compiles instead of choking on internal ambiguity.


Cheers!,

- Alf (hypothesizing mode)

blt_Fh...@3sdjijozgu.gov.uk

unread,
Apr 13, 2019, 11:53:38 AM4/13/19
to
On Fri, 12 Apr 2019 17:54:25 +0200
"Alf P. Steinbach" <alf.p.stein...@gmail.com> wrote:
>On 12.04.2019 17:48, blt_nglC4iP5z@0uwnnh_23vzpr.org wrote:
>> On Fri, 12 Apr 2019 17:39:28 +0200
>> "Alf P. Steinbach" <alf.p.stein...@gmail.com> wrote:
>>> On 12.04.2019 17:19, Mr Flibble wrote:
>>>>
>>>> constexpr explicit operator bool() const noexcept;
>>>
>>> Thanks, I forgot the `noexcept`, will add.
>>
>> Why not throw in a final too. If you're going for unreadable syntatic soup
>you
>> might as well use as many ingredients as possible.
>
><plink>

Plonker.

While people like you may think you're impressing everyone by pointlessly
using eevery bit of syntax you can find, most people will think you're simply
a showboating pillock. When you have a swiss army knife you don't have to use
every tool it has just to open a bottle.

Vir Campestris

unread,
Apr 14, 2019, 4:27:34 PM4/14/19
to
On 13/04/2019 14:11, Manfred wrote:
>>
> gcc 8.2.1 issues a warning (about the function pointer never being NULL)
> with -std=c++17 and -Wall
> It will is silent with -std=c++{14,11} regardless of -Wall

Not only are some of fighting tooth and nail to move to GCC8, but we
haven't got past C++14 yet either :(

Glad to know a fix is coming.

Andy

James Kuyper

unread,
Apr 15, 2019, 7:56:43 AM4/15/19
to
On 4/12/19 12:40 PM, Ben Bacarisse wrote:
...
> It doesn't avoid it -- it relies on it. Both the initialisation of a
> bool from a pointer, and the application of ! to a pointer, use the
> standard conversions, which is what you and Juha (and almost everyone!)
> calls implicit conversions.

As I understand it, "implicit conversions" should mean those conversions
that can occur without requiring any explicit conversion operator: a
C-style cast or one of the named casts.
The C++ standard doesn't define an "implicit conversion", but it does
define an "implicit conversion sequence" (13.3.3.1). Standard conversion
sequences are only a subset of implicit conversion sequences.
0 new messages