I study std::tuple.
Let's we have:
struct test_struct{};
I write
std::cout << typeid(std::tuple_element_t<0, std::tuple<struct test_struct &>>).name();
And I was expecting the type
struct test_struct &
But I received:
struct test_struct
How I can extract type struct test_struct & (preferably using std11)?
Thanks.
Since typeid operator does not work for reference types,
ยง5.2.8/4-5
If type is a reference type, the result refers to a std::type_info object representing the referenced type.
In all cases, cv-qualifiers are ignored by typeid (that is, typeid(T)==typeid(const T))
you can write few wrappers to find out names of reference types or types with cv-qualifiers.
template<typename T>
struct typeid_hlp
{
static std::string name() { return typeid(T).name(); }
};
template<typename T>
struct typeid_hlp<T&>
{
static std::string name() { return typeid_hlp<T>::name() + std::string(" &"); }
};
template<typename T>
struct typeid_hlp<T&&>
{
static std::string name() { return typeid_hlp<T>::name() + std::string(" &&"); }
};
template<typename T>
struct typeid_hlp<const T>
{
static std::string name() { return std::string("const ") + typeid_hlp<T>::name(); }
};
template<typename T>
struct typeid_hlp<volatile T>
{
static std::string name() { return std::string("volatile ") + typeid_hlp<T>::name(); }
};
And use it like
int main()
{
std::cout << typeid_hlp<int>::name() << std::endl; // int
std::cout << typeid_hlp<int&>::name() << std::endl; // int &
std::cout << typeid_hlp<const int>::name() << std::endl; // const int
std::cout << typeid_hlp<volatile const int * const &>::name() << std::endl; // const int const volatile * __ptr64 &
}
Related
I need to convert some numbers (integers and doubles) into std::strings, and for performance reasons cannot use stringstream (we found it to be very slow when used concurrently)
It would be nice to be able to do something like
template<typename T>
static const std::string numberToString(T number)
{
char res[25];
// next line is a bit pseduo-y
snprintf(res, sizeof(res), "%T", number);
return string(res);
}
But I'm not really sure how is the best way to achieve this?
Here's one idea. Use:
template<typename T>
static const std::string numberToString(T number)
{
char res[25];
snprintf(res, sizeof(res), getPrintfFormat<T>(), number);
return res;
}
Sample program:
#include <iostream>
#include <cstdio>
#include <string>
template <typename T> struct PrintfFormat;
template <> struct PrintfFormat<int>
{
static char const* get() { return "%d"; }
};
template <> struct PrintfFormat<float>
{
static char const* get() { return "%f"; }
};
template <> struct PrintfFormat<double>
{
static char const* get() { return "%f"; }
};
template <typename T>
char const* getPrintfFormat()
{
return PrintfFormat<T>::get();
}
template<typename T>
static const std::string numberToString(T number)
{
char res[25];
snprintf(res, sizeof(res), getPrintfFormat<T>(), number);
return res;
}
int main()
{
std::cout << numberToString(10) << std::endl;
std::cout << numberToString(10.2f) << std::endl;
std::cout << numberToString(23.456) << std::endl;
}
Output:
10
10.200000
23.456000
It also provides a level of type safety. With the posted code, using
std::cout << numberToString('A') << std::endl;
will result in a compile time error.
I want template specilization with two parameters in one function. Here is a sample of code.
#include <iostream>
#include <string>
template <typename T>
class Printer
{
public:
T value;
Printer(T value)
{
this->value = value;
}
void print();
};
template <typename T> void Printer<T>::print()
{
std::cout << value << "\n";
}
template <> void Printer<std::string>::print()
{
std::cout << "\"" << value <<"\"\n";
}
template <> void Printer<const char *>::print()
{
std::cout << "\"" << value <<"\"\n";
}
int main()
{
Printer<int> print1(2);
Printer<std::string> print2("Printing string");
Printer<const char *> print3("Printing char*");
print1.print();
print2.print();
print3.print();
}
Is there a way I can make the template speciazation for std::string and const char * in one function. I want this because they are doing the same thing.
You can use traits to add indirection on the specific behavior, based on type.
#include <iostream>
#include <string>
template <typename T>
class Printer
{
public:
T value;
Printer(T value)
{
this->value = value;
}
void print();
};
template<typename T>
struct PrinterTypeTraits {
static constexpr char* prefix = "";
static constexpr char* postfix = "";
};
template<>
struct PrinterTypeTraits<std::string> {
static constexpr char prefix = '\"';
static constexpr char postfix = '\"';
};
template<>
struct PrinterTypeTraits<const char*> : PrinterTypeTraits<std::string> {};
template <typename T> void Printer<T>::print()
{
using Traits = PrinterTypeTraits<T>;
std::cout << Traits::prefix << value << Traits::postfix << '\n';
}
int main()
{
Printer<int> print1(2);
Printer<std::string> print2("Printing string");
Printer<const char *> print3("Printing char*");
print1.print();
print2.print();
print3.print();
return 0;
}
Regarding to this code review, is it possible to also assign a size_t to a type? i.e.:
template <size_t N>
struct IntToType {
typedef ??? type; // ???
};
TypeID::value<int>(); // "assigns" 0 to int
IDType<0>::type; // resolves to int
TypeID::value<IDType<0>::type>(); // resolves to 0
I think it's just impossible by language design, this kind of recursion is probably impossible because it may depend on the order the code is being compiled, but I'll ask anyway.
It's ok to have any other way of defining an unique ID for each type if the other way around works.
I'm not a templates expert by any means, so I don't know of any loopholes in this, but it seems you could hard-wire type info using template specializations as follows:
template <typename T>
struct TypeId {
};
template <>
struct TypeId<int> {
static const size_t value = 0;
};
template <>
struct TypeId<unsigned> {
static const size_t value = 1;
};
template <>
struct TypeId<long> {
static const size_t value = 2;
};
template <>
struct TypeId<unsigned long> {
static const size_t value = 3;
};
template <>
struct TypeId<float> {
static const size_t value = 4;
};
template <>
struct TypeId<double> {
static const size_t value = 5;
};
// ------
template <size_t N>
struct TypeInfo {
};
template <>
struct TypeInfo<TypeId<int>::value> {
typedef int type;
static constexpr char const* name = "int";
};
template <>
struct TypeInfo<TypeId<unsigned>::value> {
typedef unsigned type;
static constexpr char const* name = "unsigned int";
};
template <>
struct TypeInfo<TypeId<long>::value> {
typedef long type;
static constexpr char const* name = "long int";
};
template <>
struct TypeInfo<TypeId<unsigned long>::value> {
typedef unsigned long type;
static constexpr char const* name = "unsigned long int";
};
template <>
struct TypeInfo<TypeId<float>::value> {
typedef float type;
static constexpr char const* name = "float";
};
template <>
struct TypeInfo<TypeId<double>::value> {
typedef double type;
static constexpr char const* name = "double";
};
// ---
void func(int i)
{
std::cout << "func int\n";
std::cout << TypeInfo<TypeId<decltype(i)>::value>::name << '\n';
}
void func(float f)
{
std::cout << "func float\n";
std::cout << TypeInfo<TypeId<decltype(f)>::value>::name << '\n';
}
int main()
{
TypeInfo<0>::type n1 = {};
TypeInfo<4>::type n2 = {};
func(n1);
func(n2);
std::cout << TypeInfo<TypeId<int>::value>::name << ": " << TypeId<int>::value << '\n';
std::cout << TypeInfo<TypeId<unsigned>::value>::name << ": " << TypeId<unsigned>::value << '\n';
std::cout << TypeInfo<TypeId<double>::value>::name << ": " << TypeId<double>::value << '\n';
}
Output:
func int
int
func float
float
int: 0
unsigned int: 1
double: 5
I'm relatively new to C++. Please excuse my terminology if it's incorrect. I tried searching around for an answer to my question, but I could not find it (probably because I couldn't phrase my question correctly). I'd appreciate it if someone could help me.
I am trying to write a class for creating strings that might contain the textual representation of objects or native types. Essentially, I have
private:
stringstream ss;
public:
template< typename T >
Message& operator<<( const T& value ) {
ss << value;
return *this;
}
The overloaded << operator takes some value and tries to stream it into a stringstream. I think my compiler is fine with this if the T is something like int or if the class T defines the method operator std::string(). However, if T is some type like vector<int>, then it no longer works because vector<int> doesn't define operator std::string().
Is there anyway I could perhaps overload this operator so that if T defines operator std::string(), then I print the textual representation, and if it doesn't, I just print its address?
Thanks.
This can be implemented by building upon the has_insertion_operator type trait described here: https://stackoverflow.com/a/5771273/4323
namespace has_insertion_operator_impl {
typedef char no;
typedef char yes[2];
struct any_t {
template<typename T> any_t( T const& );
};
no operator<<( std::ostream const&, any_t const& );
yes& test( std::ostream& );
no test( no );
template<typename T>
struct has_insertion_operator {
static std::ostream &s;
static T const &t;
static bool const value = sizeof( test(s << t) ) == sizeof( yes );
};
}
template<typename T>
struct has_insertion_operator :
has_insertion_operator_impl::has_insertion_operator<T> {
};
Once we have that, the rest is relatively straightforward:
class Message
{
std::ostringstream ss;
public:
template< typename T >
typename std::enable_if<has_insertion_operator<T>::value, Message&>::type
operator<<( const T& value ) {
ss << value;
return *this;
}
template< typename T >
typename std::enable_if<!has_insertion_operator<T>::value, Message&>::type
operator<<( const T& value ) {
ss << &value;
return *this;
}
};
That is, if there is an insertion operator defined, print the value, otherwise print its address.
This does not rely on a conversion-to-std::string operator being defined--you only need to make sure your T instances are "printable" using operator << (typically implemented in the same scope where each T is defined, e.g. namespace or global scope).
Here's an example - using some custom traits for a conversion operator to std::string and the streaming operator:
#include <iostream>
#include <string>
template <class T>
struct traits
{
template <typename Q>
static auto hos(Q*) -> decltype(std::declval<const Q>().operator std::string());
static char hos(...);
constexpr static bool has_operator_string =
sizeof hos((T*){0}) != 1;
// ----
template <typename Q>
static auto isab(Q*) -> decltype(std::cout << std::declval<const Q>());
static char isab(...);
constexpr static bool is_streamable =
sizeof isab((T*){0}) != 1;
};
struct S
{
template <typename T>
typename std::enable_if<
traits<T>::has_operator_string,
S&>::type
operator<<(const T& value)
{
std::cout << "string() " << value.operator std::string() << '\n';
return *this;
}
template <typename T>
typename std::enable_if<!traits<T>::has_operator_string && traits<T>::is_streamable, S&>::type
operator<<(const T& value)
{
std::cout << "<< " << value << std::endl;
return *this;
}
template <typename T>
typename std::enable_if<
!traits<T>::has_operator_string &&
!traits<T>::is_streamable,
S&>::type
operator<<(const T& value)
{
std::cout << "T& #" << &value << std::endl;
return *this;
}
};
struct X
{
operator std::string() const { return "hi"; }
};
struct Y
{
};
int main()
{
std::cout << "> main()" << std::endl;
std::cout << "X() ";
S() << X();
Y y;
std::cout << "Y y; ";
S() << y;
std::cout << "Y() ";
S() << Y();
std::cout << "\"text\" ";
S() << "text";
std::cout << "< main()" << std::endl;
}
BACKGROUND
I have a container class that has a std::vector<T> member that I initialize with the constructor that takes size_t n_items. I would like to initialize that vector with my own Zero() function which returns 0; by default, but if static member T::Zero exists I want to return that instead.
In my first attempt, I use expression SFINAE, but that failed due to ambiguous overload since both the generic version of Zero and the Zero have the same signature with no arguments. So now, I'm trying to convert the code into classes with operator().
I think I need to use std::enable_if somehow, but I'm not sure how to go about coding this.
FAILED ATTEMPT
#include <cassert>
#include <iostream>
#include <vector>
template<typename T>
struct Zero
{
T operator() const { return 0; }
};
template<typename T>
struct Zero
{
auto operator() const ->
decltype( T::Zero )
{
return T::Zero;
}
};
struct Foo
{
char m_c;
static Foo Zero;
Foo() : m_c( 'a' ) { }
Foo( char c ) : m_c( c ) { }
bool operator==( Foo const& rhs ) const { return m_c==rhs.m_c; }
friend std::ostream& operator<<( std::ostream& os, Foo const& rhs )
{
os << (char)(rhs.m_c);
return os;
}
};
Foo Foo::Zero( 'z' );
int
main( int argc, char** argv )
{
std::vector<unsigned> v( 5, Zero<unsigned>() );
std::vector<Foo> w( 3, Zero<Foo>() );
for( auto& x : v )
std::cout << x << "\n";
std::cout << "---------------------------------\n";
for( auto& x : w )
{
assert( x==Foo::Zero );
std::cout << x << "\n";
}
std::cout << "ZERO = " << Foo::Zero << "\n";
return 0;
}
#include <string>
#include <iostream>
#include <vector>
#include <type_traits>
namespace detail
{
template<class T, class = decltype(T::zero)>
std::true_type has_zero_impl(int);
template<class T>
std::false_type has_zero_impl(short);
}
template<class T>
using has_zero = decltype(detail::has_zero_impl<T>(0));
template<class T, class = has_zero<T>>
struct zero
{
constexpr static T get() { return T(); }
};
template<class T>
struct zero<T, std::true_type>
{
constexpr static auto get() -> decltype(T::zero)
{ return T::zero; }
};
Usage example:
template<>
struct zero<std::string>
{
static constexpr const char* get()
{ return "[Empty]"; }
};
struct foo
{
int m;
static constexpr int zero = 42;
};
int main()
{
std::cout << zero<int>::get() << "\n";
std::cout << zero<std::string>::get() << "\n";
std::cout << zero<foo>::get() << "\n";
}
Compact version w/o trait:
template<class T>
struct zero
{
private:
template<class X>
constexpr static decltype(X::zero) zero_impl(int)
{ return X::zero; }
template<class X>
constexpr static X zero_impl(short)
{ return X(); }
public:
constexpr static auto get()
-> decltype(zero_impl<T>(0))
{
return zero_impl<T>(0);
}
};
template<>
struct zero<std::string>
{
constexpr static const char* get()
{ return "[Empty]"; }
};
Maybe:
#include <iostream>
#include <vector>
template <typename T>
inline T zero() {
return T();
}
template <>
inline std::string zero<std::string>() {
return "[Empty]";
}
int main() {
std::vector<std::string> v(1, zero<std::string>());
std::cout << v[0] << '\n';
}
I have a half good news: I found a very simple way (leveraging SFINAE), however the output is not exactly what I expected :)
#include <iostream>
#include <string>
#include <vector>
// Meat
template <typename T, typename = decltype(T::Zero)>
auto zero_init_impl(int) -> T { return T::Zero; }
template <typename T>
auto zero_init_impl(...) -> T { return T{}; }
template <typename T>
auto zero_init() -> T { return zero_init_impl<T>(0); }
// Example
struct Special { static Special const Zero; std::string data; };
Special const Special::Zero = { "Empty" };
int main() {
std::vector<int> const v{3, zero_init<int>()};
std::vector<Special> const v2{3, zero_init<Special>()};
std::cout << v[0] << ", " << v[1] << ", " << v[2] << "\n";
std::cout << v2[0].data << ", " << v2[1].data << ", " << v2[2].data << "\n";
return 0;
}
As mentioned, the result is surprising was explained by dyp, we have to be careful not use std::initializer<int> by mistake and then read past the end:
3, 0, 0
Empty, Empty, Empty
Curly brace initialization yields a different result than regular brace initialization (see here) which gives the expected 0, 0, 0. So you have to use regular braces.