Summary: Simplify to get a more readable warning message, then compare the message to a possibly better-recognized case. This is more of a work-through answer (teach to fish) than a direct explanation (give a fish).
This is one of the cases where really working at a minimal reproducible example can have benefits. I acknowledge that some of the complication was kept "just to make a case", but let's drop that for now.
The three lines in main
each trigger the same warning, so simplify to just one of those lines. Preferably, we keep a line whose output is unexpected, such as the first of the three lines (int
is not a floating point type, so my_floating_point<int>::value
is intended to be false). That cuts the compiler's messages to a third of what they were and helps identify which messages go together (at this point, they all go together).
With only one type to consider, we no longer need to my_floating_point
to be a template. Templates sometimes add a significant amount of insignificant detail to warnings (such as – in this case – the required from here
message), so drop the template and replace std::is_floating_point_v<T>
with std::is_floating_point_v<int>
. This reduces the warning down to one message plus the indication of where the warning occurred.
One more simplification: take value
outside the struct
, allowing my_floating_point
to be eliminated. Admittedly, this does not have much impact on the error message, but it does remove a red herring from the example code.
#include <iostream>
static constexpr bool value = []()
{
if constexpr(std::is_floating_point_v<int>) { return true; }
else { return false; }
}; // compilation warning
int main()
{
std::cout << value << std::endl;
}
prog.cc:7:1: warning: the address of 'static constexpr bool<lambda()>::_FUN()' will never be NULL [-Waddress]
7 | }; // compilation warning
| ^
Note that this is almost one of the lines from the question's compiler output. The only difference is the removal of my_floating_point<int>::
which corresponds nicely with the simplifications we did.
OK, now that we have the situation suitably simplified, let's compare the warning to one produced in a slightly different setup. Instead of a lambda, let's use an official function. The goal is to gain some basic (yet imprecise) understanding by by comparing similar scenarios.
Don't get hung up on "how would I think to do this?" This is something I knew to do because I recalled a remarkably similar warning from a different setup. The first part of this answer presented steps that I think are reasonable to expect from others. In contrast, this part of this answer requires familiarity with messages from the compiler.
#include <iostream>
bool fun()
{
if constexpr(std::is_floating_point_v<int>) { return true; }
else { return false; }
}
static constexpr bool value = fun; // compilation warning
int main()
{
std::cout << value << std::endl;
}
prog.cc:9:31: warning: the address of 'bool fun()' will never be NULL [-Waddress]
9 | static constexpr bool value = fun; // compilation warning
| ^~~
Again, the same warning that the address of [something] will never be NULL. (Perhaps you already see where this is going?) In this code, since the function is not invoked, the symbol fun
becomes a pointer to the function. Assigning a pointer to a bool
results in true
if and only if the pointer is non-null. This particular pointer cannot be null because it is the address of something. So the compiler throws out a warning; the code is syntactically valid, but you probably meant to invoke the function (by adding parentheses just before the semicolon, as in fun()
instead of just fun
).
Similar mechanics are in play for the code with a lambda. When the lambda is not invoked, it can convert to a bool
, becoming true
if and only if there is a lambda. As in the function case, the result has to be true
. The compiler throws out a warning; the code is syntactically valid, but you probably meant to invoke the lambda (by adding parentheses just before the semicolon).
static constexpr bool value = []()
{
if constexpr(std::is_floating_point_v<int>) { return true; }
else { return false; }
}(); // no compilation warning with the parentheses
Even better, the output is now 0
, as intended.
OK, the short version is "add parentheses", but the real lesson of this answer is the usefulness of recognizing compiler messages. When a warning is worded similarly to one you've encountered before, try to replicate the warning you are familiar with. See if there are similarities that allow you to transfer a solution from the familiar case to the less familiar one.
Familiarity takes time, but it takes less time if you make it a goal. ;)