function-style-cast in Template Meta programming

98 Views Asked by At

Code taken from the book Template Metaprogramming with C++, it doesn't compile i tried visual studio 22 i get the error:

Error   C2440

\<function-style-cast\>'

: cannot convert from 'initializer list' to 'n713::async_bool'chapter_07
see code:
class async_bool{
    std::function<bool()> check;
    public:explicit async_bool() = delete;
    async_bool(std::function<bool()> checkIt): check(checkIt){ }

      async_bool(bool val)
         : check([val]() {return val; })
      { }
    
      static async_bool yes() {
          return async_bool(
              []() { return true; } ); 
      }
      static async_bool no() {
          return async_bool(
              []() { return false; } ); 
      }
    
      bool operator&&(bool fore) const { return fore && check(); }
      bool operator!() const { return !check(); }
      operator bool() const { return check(); }
};
int main(){
    async_bool b1 = async_bool(false);  //async_bool b1{ false };
    async_bool b2 = async_bool(true);// async_bool b2{ true };
    async_bool b3{  {std::cout << "Y/N? "; char c; std::cin >> c; return c == 'Y' || c == 'y'; }
    if (b1) { std::cout << "b1 is true\n"; }
    if (b2) { std::cout << "b2 is true\n"; }
    if (b3) { std::cout << "b3 is true\n"; }
    return 0;
};

tried c++20 with visual studio tried g++ in ubuntu-> gave different errors but still didnt compile, managed to fix it i think by changing the code to the following:


class async_bool

    {
        using check = std::function<bool()>;
        check dec_;


    public:
        async_bool() = delete;
        async_bool(check dec) : dec_{ std::move(dec) } {}

        
        async_bool(bool val) :dec_([val]() {return val; }) {}

        static async_bool yes() {
            const auto lam = []() { return true; };
            async_bool async_bool_yes(lam());

            return async_bool_yes;
        }

        static async_bool no() {
            const auto lam = []() { return false; };
            async_bool async_bool_no(lam());
            return async_bool_no;
        }

  

        bool operator&&(bool fore) const { return fore && dec_(); }

        bool operator!() const { return !dec_(); }

        operator bool() const { return dec_(); }

    };


and in main:


int main()
{
    async_bool b1( false );
    async_bool b2{ true };
    const auto lam = []() { []() {std::cout << "Y/N? "; char c; std::cin >> c; return c == 'Y' || c == 'y'; }; };
    async_bool b3{lam};
    return 0;
}
1

There are 1 best solutions below

0
On

Lambdas that don't capture anything are convertible both to std::function and to bool (via conversion to function pointer). You can add an additional templated constructor to make compiler prefer conversion to std::function:

template <typename F,
    typename = std::enable_if_t<std::is_convertible_v<F,std::function<bool()>>>>
async_bool(F checkIt): check(checkIt) { }

Alternatively, instead of SFINAE you can use concepts.

(Edit: it's interesting that removing the constructor from std::function removes the ambiguity, but every construction with a { <captureless-lambda> } still fails because conversion from a function pointer to a bool is forbidden using braces, but the corresponding candidate it is not removed from overload-set. Maybe language lawyers can explain this bit if you're interested.