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
.
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.
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.
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.
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.
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;
}
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&
.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With