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.
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&.
Related
I want to know if it's possible to have the same function but for different type like in c++ for Typescript ?
#include <iostream>
template <typename T>
void print(double x)
{
std::cout << "IS DOUBLE: " << x << std::endl;
}
template <typename T>
void print(int x)
{
std::cout << "IS INT: " << x << std::endl;
}
template <typename T>
void print(std::string x)
{
std::cout << "IS STRING: " << x << std::endl;
}
int main()
{
print<int>(2);
print<double>(8.0);
print<std::string>("HA");
return 0;
}
There is the output
IS INT: 2
IS DOUBLE: 8
IS STRING: HA
Taking this example: https://godbolt.org/z/gHqCSA
#include<iostream>
template<typename Return, typename... Args>
std::ostream& operator <<(std::ostream& os, Return(*p)(Args...) ) {
return os << (void*)p;
}
template <typename ClassType, typename Return, typename... Args>
std::ostream& operator <<(std::ostream& os, Return (ClassType::*p)(Args...) )
{
unsigned char* internal_representation = reinterpret_cast<unsigned char*>(&p);
os << "0x" << std::hex;
for(int i = 0; i < sizeof p; i++) {
os << (int)internal_representation[i];
}
return os;
}
struct test_debugger { void var() {} };
void fun_void_void(){};
void fun_void_double(double d){};
double fun_double_double(double d){return d;}
int main() {
std::cout << "0. " << &test_debugger::var << std::endl;
std::cout << "1. " << fun_void_void << std::endl;
std::cout << "2. " << fun_void_double << std::endl;
std::cout << "3. " << fun_double_double << std::endl;
}
// Prints:
// 0. 0x7018400100000000000
// 1. 0x100401080
// 2. 0x100401087
// 3. 0x100401093
I see the address of the member function is 0x7018400100000000000, which is understandable because member functions pointers have 16 bytes while free function as 0x100401080 have only 8 bytes.
However, why the member function address 0x7018400100000000000 is so far away from free function address 0x100401080? i.e., |0x7018400100000000000 - 0x100401080| = 0x70184000FFEFFBFEF80?
Why it is not closer i.e., something like 0x100401... instead of 0x701840...? Or I am printing the member function address wrong?
Your architecture is little-endian. The low byte of the address is in the first byte of p, so your address is being printed out backwards.
Fixed code which automatically detects little/big endian: https://godbolt.org/z/XSvT5R
#include <iostream>
#include <iomanip>
#include <sstream>
inline bool is_big_endian() {
long int longvalue = 1;
// https://stackoverflow.com/questions/8978935/detecting-endianness
unsigned char* representation = reinterpret_cast<unsigned char*>(&longvalue);
return ( (unsigned) representation[sizeof(long int) - 1] ) == 1;
}
template<typename Pointer>
std::ostream& print_pointer(std::ostream& os, const Pointer& pointer) {
const unsigned char* representation = (unsigned char*) &pointer;
int precision = 0;
bool haszeros = false;
unsigned firsthexdigit;
unsigned secondhexdigit;
std::ostringstream stream;
stream.flags( os.flags() );
stream << std::hex;
#define print_pointer_HEX_DIGIT \
firsthexdigit = (unsigned) representation[index] >> 4 & 0xf; \
secondhexdigit = (unsigned) representation[index] & 0xf; \
if( haszeros || firsthexdigit ) { \
precision++; \
haszeros = true ; \
stream << firsthexdigit; \
} \
if( haszeros || secondhexdigit ) { \
precision++; \
haszeros = true ; \
stream << secondhexdigit; \
}
if( is_big_endian() ) {
for(int index = 0; index < static_cast<int>(sizeof pointer); index++) {
print_pointer_HEX_DIGIT
}
}
else {
for(int index = static_cast<int>(sizeof pointer - 1); index >= 0 ; index--) {
print_pointer_HEX_DIGIT
}
}
if( os.precision() - ++precision > 0 ) {
return os << "0x" + std::string( os.precision() - ++precision, '0' ) + stream.str();
}
return os << "0x" + stream.str();
}
template<typename Return, typename... Args>
std::ostream& operator <<(std::ostream& os, Return(*pointer)(Args...) ) {
return print_pointer(os , pointer);
}
template <typename ClassType, typename Return, typename... Args>
std::ostream& operator <<(std::ostream& os, Return (ClassType::*pointer)(Args...) ) {
return print_pointer(os , pointer);
}
struct test_debugger { void var() {} };
void fun_void_void(){};
void fun_void_double(double d){};
double fun_double_double(double d){return d;}
int main() {
std::cout << "0. " << &test_debugger::var << std::endl;
std::cout << "1. " << fun_void_void << std::endl;
std::cout << "2. " << fun_void_double << std::endl;
std::cout << "3. " << fun_double_double << std::endl;
std::cout << "4. " << std::setfill('0') << std::setw(16) << fun_void_void << std::endl;
std::cout << "5. " << std::setprecision(16) << fun_void_double << std::endl;
}
// Prints:
// 0. 0x100402e80
// 1. 0x100401118
// 2. 0x10040111f
// 3. 0x10040112b
// 4. 000000x100401118
// 5. 0x0000010040111f
I'm trying to dispatch my calls in 2 different functions. One for pointers and the other for references. But as soon as I use the const qualifier, templates doesn't dispatch as expected. In my case, the get_pixel doesn't use any const qualifier because it is supposed to edit the given parameter. And set_pixel is supposed to use the given parameter but don't edit it and I would like those parameters to remain const.
#include <iostream>
template <typename Color>
inline int get_pixel(
Color& color)
{
return 1;
}
template <typename T>
inline int get_pixel(
T components[])
{
return 2;
}
template <typename Color>
inline int set_pixel(
const Color& color)
{
return 1;
}
template <typename T>
inline int set_pixel(
const T components[])
{
return 2;
}
template <typename Color>
inline int set_pixel_no_const(
Color& color)
{
return 1;
}
template <typename T>
inline int set_pixel_no_const(
T components[])
{
return 2;
}
int main()
{
float c;
float tab[1];
std::cout << "Get PIXEL\n";
std::cout << "Dispatch for c : " << get_pixel(c) << "\n"; // 1
std::cout << "Dispatch for &c : " << get_pixel(&c) << "\n"; // 2
std::cout << "Dispatch for tab : " << get_pixel(tab) << "\n"; // 2
std::cout << "Set PIXEL\n";
std::cout << "Dispatch for c : " << set_pixel(c) << "\n"; // 1
std::cout << "Dispatch for &c : " << set_pixel(&c) << "\n"; // 1, Should be 2
std::cout << "Dispatch for tab : " << set_pixel(tab) << "\n"; // 1, Should be 2
std::cout << "Set PIXEL NO CONST\n";
std::cout << "Dispatch for c : " << set_pixel_no_const(c) << "\n"; // 1
std::cout << "Dispatch for &c : " << set_pixel_no_const(&c) << "\n"; // 2
std::cout << "Dispatch for tab : " << set_pixel_no_const(tab) << "\n"; // 2
return 0;
}
Any idea why the const qualifier is a problem here ?
The template deduction doesn't work as a text substitution, but on the T as a whole.
When T in const T is deduced as float* you don't get const float*, but float* const.
Or const (float*), if we had such a syntax.
I may be wrong, but i think basically this question boils down to this:
#include <iostream>
template <typename T>
int f(T const &)
{
//std::cout << __PRETTY_FUNCTION__ << "\n";
return 1;
}
template <typename T>
int f(T const *)
{
//std::cout << __PRETTY_FUNCTION__ << "\n";
return 2;
}
int main()
{
float c = 1.f;
float * addr = &c;
float const * addr_const = &c;
f(c); // 1
f(&c); // 1 you expected 2
f(addr); // 1 you expected 2
f(addr_const); // 2 as you expect
return 0;
}
Your const array function parameter is the same as a const pointer parameter in the function declaration(so i put it in this way in the example).
I think the first function is the base template, while the second version is a more specialized version (since it only takes pointers to const T). So the const reference one gets chosen when you pass a pointer to non const. Except in the case you really pass it a pointer to const as argument.
If you use gcc (i think) you can use __PRETTY_FUNCTION__ to display the deduced arguments
Why b.isEm() prints different things on different lines when I have not changed anything after the last call of b.isEm()?
#include <iostream>
#include <string>
template <class T>
class Box
{
bool m_i;
T m_c;
public:
bool isEm() const;
void put(const T& c);
T get();
};
template <class T>
bool Box<T>::isEm() const
{
return m_i;
}
template <class T>
void Box<T>::put(const T& c)
{
m_i = false;
m_c = c;
}
template <class T>
T Box<T>::get()
{
m_i = true;
return T();
}
int main()
{
Box<int> b;
b.put(10);
std::cout << b.get() << " " << b.isEm() << std::endl;
std::cout << b.isEm() << std::endl;
}
The order of evaluation of function arguments in C++ is unspecified.
std::cout << b.get() << " " << b.isEm() << std::endl;
std::cout << b.isEm() << std::endl;
Since b.get() has side effects, I suggest you call it separately...
auto g = b.get();
std::cout << g << " " << b.isEm() << std::endl;
std::cout << b.isEm() << std::endl;
Note: std::cout << .... << ... << is a function call with the arguments ...
We see std::is_const<const int&>::value is always false.So this instruction #1 is never execute.
template <typename T> void g(T&& val)
{
if(is_const<T>::value)
{
#1 if(is_lvalue_reference<T>::value)cout<<"const l reference"<<endl;
else if(is_rvalue_reference<T>::value)cout<<"const r reference"<<endl;
else cout<<"const int"<<endl;
}else
{
if(is_lvalue_reference<T>::value)cout<<"l reference"<<endl;
else if(is_rvalue_reference<T>::value)cout<<" r reference"<<endl;
else cout<<" int"<<endl;
}
}
Why STL not provide is_reference_const function for this issue?And Can we write this function for this?
At last, this function such as is_reference_const<const int&>::value is ture.
Anything is in the standard because someone wanted it there and put the energy into getting it there and convinced the committee it was a good idea.
This works:
#include <type_traits>
#include <iostream>
template <typename T>
struct is_reference_const
{
static const bool value = std::is_reference<T>::value && std::is_const<typename std::remove_reference<T>::type>::value;
};
int main()
{
std::cout << is_reference_const<const int &>::value << std::endl;
std::cout << is_reference_const<const int>::value << std::endl;
std::cout << is_reference_const<int &>::value << std::endl;
std::cout << is_reference_const<int>::value << std::endl;
}
1
0
0
0
I was surprised that is_const<const int&>::value was false.