Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Recognize that a value is bool in a template

Tags:

c++

c++17

This short C++17 program:

#include <iostream>

template <typename T> void output(T x)
{
    if constexpr (std::is_integral<decltype(x)>::value) {
        std::cout << static_cast<int>(x) << " is integral" << std::endl;
    } else {
        std::cout << x << " is not integral" << std::endl;
    }
}

int main()
{
    char x = 65;
    output(x);

    bool t = true;
    output(t);

    return 0;
}

Has this output:

65 is integral
1 is integral

In the template function named output, how can one detect that the argument x is boolean and not a number?

The plan is to output the value with std::cout << std::boolalpha <<, but only if the type is bool.

like image 445
Alexander Avatar asked Aug 15 '18 12:08

Alexander


People also ask

Can you use == in a boolean statement?

You don't need == '1' or same as or anything like that, because it directly evaluates as to a boolean value. I also wouldn't recommend to use type safe checks with content entities because they are not type safe.

Why are my Boolean variables not being dereferenced correctly?

If you have a boolean variable and a pointer to a boolean variable in a template, the behavior of the dereferenced values in the template vary incorrectly. The pointer to the boolean seems to be dereferenced correctly but the logical not operator applied to it does not yield the correct result.

How to check if a boolean is true or false?

The pointer to the boolean seems to be dereferenced correctly but the logical not operator applied to it does not yield the correct result. a pointer value is considered true if it is not nil.

Where are values stored in a boolean field?

Values are stored in the database and anything coming out from there is a string but sometimes values might not be. The boolean field is actually the perfect example for that, it is a string one, aka a nice mix of 3 different data types.


2 Answers

std::is_integral checks if a type is one of the following types: bool, char, char16_t, char32_t, wchar_t, short, int, long, long long (source). If you want to check if a type is the same as another type, std::is_same can be used. Both can be combined to get the wanted result:

template <typename T> void output(T x)
{
    if constexpr (std::is_integral<decltype(x)>::value && !std::is_same<decltype(x), bool>::value) {
        std::cout << static_cast<int>(x) << " is integral but not a boolean" << std::endl;
    } else {
        std::cout << x << " is not integral" << std::endl;
    }
}

or, since we already know the type of decltype(x), which is T:

template <typename T> void output(T x)
{
    if constexpr (std::is_integral<T>::value && !std::is_same<T, bool>::value) {
        std::cout << static_cast<int>(x) << " is integral but not a boolean" << std::endl;
    } else {
        std::cout << x << " is not integral" << std::endl;
    }
}

Another way can be to use a template specialization. This makes sure the other overload is being used to handle the boolean value.

template <typename T> void output(T x)
{
    if constexpr (std::is_integral<T>::value) {
        std::cout << static_cast<int>(x) << " is integral but not a boolean" << std::endl;
    } else {
        std::cout << x << " is not integral" << std::endl;
    }
}

template <> void output(bool x)
{
    std::cout << x << " is a boolean" << std::endl;
}
like image 143
Caramiriel Avatar answered Oct 18 '22 22:10

Caramiriel


namespace fmt {
  namespace adl {
    template<class T>
    void output( std::ostream& os, T const& t ) {
      os << t;
    }
    void output( std::ostream& os, bool const& b ) {
      auto old = os.flags();
      os << std::boolalpha << b;
      if (!( old & std::ios_base::boolalpha) )
        os << std::noboolalpha; // restore state
    }
    template<class T>
    void output_helper( std::ostream& os, T const& t ) {
      output(os, t); // ADL
    }
  }
  template<class T>
  std::ostream& output( std::ostream& os, T const& t ) {
    adl::output_helper( os, t );
    return os;
  }
}

now fmt::output( std::cout, true ) prints true, while fmt::output( std::cout, 7 ) prints 7.

You can extend fmt::output by creating a function in either fmt::adl or in the type T's namespace called output that takes a std::ostream& and a T const&.

like image 39
Yakk - Adam Nevraumont Avatar answered Oct 18 '22 22:10

Yakk - Adam Nevraumont