Search code examples
c++templateslambdaif-constexpr

Initialization of static bool with lambda and constexpr-if gives adress error


I was trying to implement a certain type trait, but faced this following error.

Here is a simple program that shows the behavior:

#include <iostream>

template<typename T>
struct my_floating_point // just to make a case
{
    // static constexpr bool value = std::is_floating_point_v<T>;
    // THIS WORKS

    static constexpr bool value = []()
    {
        if constexpr(std::is_floating_point_v<T>) { return true; }
        else { return false; }
    }; // compilation error
};

int main()
{
    std::cout << my_floating_point<int>::value << std::endl;
    std::cout << my_floating_point<double>::value << std::endl;
    std::cout << my_floating_point<char>::value << std::endl;
}

The commented line works just fine. However, the uncommented piece of code gives this warning with g++:

g++ -std=c++17 -O3 main.cpp -Wall -Wextra -pedantic
main.cpp: In instantiation of ‘constexpr const bool my_floating_point<int>::value’:
main.cpp:18:39:   required from here
main.cpp:9:24: warning: the address of ‘static constexpr bool my_floating_point<int>::<lambda()>::_FUN()’ will never be NULL [-Waddress]
  static constexpr bool value = []()
                        ^~~~~
main.cpp:9:24: warning: the address of ‘static constexpr bool my_floating_point<int>::<lambda()>::_FUN()’ will never be NULL [-Waddress]

And running it outputs

1
1
1

What is wrong?

Note: clang++ for some reason doesn't give warning, but outputs the same.


Solution

  •  []()
        {
          // ...
        }
    

    A lambda expression evaluates to an instance of an anonymous type. That's what a lambda really is: an object whose type is unspecified. Attempting to assign an instance of this object to a bool is not valid C++.

    The good news is that this anonymous type has an operator() overload, that just happens, accidentally, to return a bool. So, for example, this will work:

    static constexpr bool value = []()
    {
        if constexpr(std::is_floating_point_v<T>) { return true; }
        else { return false; }
    }(); // compiles just fine.