I'm trying to differentiate between user types and primitive types in a variadic template.
I have tried overloading binary operator, but that only says that there's no fitting overload for 'user types'...
template <typename T>
void PrintParams(T t)
{
if (IsAUserType)
std::cout << typeid(t).name();
else
std::cout << t;
}
template <typename First, typename... Rest>
void PrintParams(First first, Rest... rest)
{
if (IsAUserType)
std::cout << typeid(first).name();
else
std::cout << first;
PrintParams(rest...);
}
// If you know what to do with this, then that would also be very helpful...
//Overload << operator for user types
//template <typename T>
//friend std::ostream& operator<< (std::ostream& os, T t)
//{
//
//if (std::is_fundamental<t>::value)
//std::clog << t;
//else
//std::clog << typeid(t).name();
//}
expected result for input like (class test, 3.4, "string") would be
"test3.4string"
You could split your single argument function up in two and use SFINAE to enable the correct one depending on if the argument is a fundamental type or not:
template<typename T, typename std::enable_if<std::is_fundamental<T>::value, int>::type = 0>
void PrintParams(T t) {
std::cout << t;
}
template<typename T, typename std::enable_if<!std::is_fundamental<T>::value, int>::type = 0>
void PrintParams(T t) {
std::cout << typeid(t).name();
}
template<typename First, typename... Rest>
void PrintParams(First first, Rest... rest) {
PrintParams(first); // ... and call the single argument version here
std::cout << ",";
PrintParams(rest...);
}
Another way would be to check if the type supports streaming using operator<< instead of checking that it's a fundamental type. That would make streaming work for classes (like std::string and user defined ones too).
#include <iostream>
#include <type_traits>
#include <typeinfo>
#include <utility>
// SFINAE support
namespace detail {
template<class>
struct sfinae_true : std::true_type {};
template<class S, class T>
static auto test_lshift(int)
-> sfinae_true<decltype(std::declval<S>() << std::declval<T>())>;
template<class S, class T>
static auto test_lshift(long) -> std::false_type;
} // namespace detail
template<class T>
struct has_ostream : decltype(detail::test_lshift<std::ostream, T>(0)) {};
// using the SFINAE support stuff
template<typename T, typename std::enable_if<has_ostream<T>::value, int>::type = 0>
void PrintParams(const T& t) {
std::cout << "Type: " << typeid(t).name() << "\n"
<< " supports operator<< Value = " << t << "\n";
}
template<typename T, typename std::enable_if<!has_ostream<T>::value, int>::type = 0>
void PrintParams(const T& t) {
std::cout << "Type: " << typeid(t).name() << "\n"
<< " does NOT support operator<<\n";
}
template<typename First, typename... Rest>
void PrintParams(First first, Rest... rest) {
PrintParams(first);
PrintParams(rest...);
}
// example classes
class Foo { // will not support streaming
int x = 5;
};
class Bar { // this should support streaming
int x = 10;
friend std::ostream& operator<<(std::ostream&, const Bar&);
};
std::ostream& operator<<(std::ostream& os, const Bar& b) {
return os << b.x;
}
// testing
int main() {
int i = 2;
Foo f;
Bar b;
std::string s = "Hello world";
PrintParams(i, f, b, s);
}
Possible output:
Type: i
supports operator<< Value = 2
Type: 3Foo
does NOT support operator<<
Type: 3Bar
supports operator<< Value = 10
Type: NSt7__cxx1112basic_stringIcSt11char_traitsIcESaIcEEE
supports operator<< Value = Hello world
I think std::is_class can replace your IsAUserType.
https://en.cppreference.com/w/cpp/types/is_class
Primitive data types include integer , character , void , float etc..which are defined already inside the language i.e , user can use these data types without defining them inside the language.
User defined data types are the data types which user have to define while or before using them.
Related
The code below comes in handy for fast debugging. It can pretty print containers like vectors from the STL while also being able to provide the printing-ness property for fundamental and streamable types using SFINAE techniques.
I would like to replicate the same behaviour without the use of decltype. Any other neat techniques of replicating this behaviour will be very helpful implementation-wise for a few projects I have in mind. The current thread may also be considered as a continuation of this thread (also by me). I managed to get a neat working implementation with concepts in C++20 (GCC 10.2.0) without the use of decltype but I would like to be able to do so in C++17 (GCC 9.2.0) and lower (obviously, without concepts, and decltype as mentioned).
namespace debugging {
template <typename T>
class range {
public:
T begin, end;
};
template <typename T>
auto make_range (const T& b, const T& e) -> range <T> {
return {b, e};
}
template <typename T>
auto is_streamable_object (T *x) -> decltype(std::cerr << *x, std::true_type());
template <typename T>
auto is_streamable_object (...) -> decltype(std::false_type());
class view {
private:
std::ostream& stream;
public:
view (std::ostream& os = std::cerr) : stream (os)
{ };
~view ()
{ stream << std::endl; };
#ifdef LOST_IN_SPACE
template <typename T>
std::enable_if_t <std::is_same <decltype(is_streamable_object <T> (nullptr)), std::true_type>::value, view&>
operator << (const T& t) {
stream << std::boolalpha << t; return *this;
}
template <typename T>
std::enable_if_t <std::is_same <decltype(is_streamable_object <T> (nullptr)), std::false_type>::value, view&>
operator << (const T& t) {
return *this << make_range(begin(t), end(t));
}
template <typename T>
view& operator << (const range <T>& r) {
stream << "[";
for (auto i = r.begin, j = i; i != r.end; ++i)
*this << *i << (++j == r.end ? "]" : ", ");
return *this;
}
template <typename A, typename B>
view& operator << (const std::pair <A, B>& p) {
stream << '(' << p.first << ", " << p.second << ')';
return *this;
}
#else
template <typename T> view& operator << (const T&)
{ return *this; }
#endif
};
} // namespace debugging
Test code in case you'd like to try it quickly yourself:
#define print(x) " [" << #x << ": " << x << "] "
using view = debugging::view;
view debug (std::cerr);
auto test () -> void {
std::vector <int> v {1,2,3,4,5};
std::map <int, int> m {{1,2}, {3,4}};
debug << print(v) print(m) << "\nHello World";
}
Sure, here's an implementation using sizeof:
template<class T, class = std::false_type>
struct is_streamable_object : std::false_type {};
template<class T>
struct is_streamable_object<T,
std::bool_constant<sizeof(std::cerr << std::declval<T>()) == 0>> : std::true_type {};
Example.
Other keywords you could use include alignof, noexcept, typeid, and explicit (the last since C++20).
Essentially, you want to perform expression SFINAE, which requires constructing an expression that is not to be evaluated. The operators that allow constructing unevaluated expressions are those mentioned above plus decltype (which you do not want to use) and requires (C++20).
In the following code, what is the difference between the following two template lines.
> 1. template<class T, std::enable_if_t<std::is_integral<T>::value, int> = 0>
> 2. template<class T, typename = std::enable_if_t<std::is_integral<T>::value>>
Both the above lines are working fine, I just wanted to know the advantages/disadvantage in using one over the other.
#include <type_traits>
#include <iostream>
template<class T, std::enable_if_t<std::is_integral<T>::value, int> = 0>
//template<class T, typename = std::enable_if_t<std::is_integral<T>::value>>
int onlyOnInt(T a, T b)
{
return a+b;
}
int main()
{
onlyOnInt(1, 2);
}
They are both working fine, if you write a single function.
But when you want two alternative functions, this way
template <typename T, typename = std::enable_if_t<true == std::is_integral_v<T>>>
void foo (T const &)
{ std::cout << "is integral" << std::endl; }
template <typename T, typename = std::enable_if_t<false == std::is_integral_v<T>>>
void foo (T const &)
{ std::cout << "isn\'t integral" << std::endl; }
you get a compilation error where this way
template <typename T, std::enable_if_t<true == std::is_integral_v<T>, int> = 0>
void foo (T const &)
{ std::cout << "is integral" << std::endl; }
template <typename T, std::enable_if_t<false == std::is_integral_v<T>, int> = 0>
void foo (T const &)
{ std::cout << "isn\'t integral" << std::endl; }
works.
The reason?
Consider you're playing with SFINAE, that is Substitution Failure Is Not An Error.
The point is Substitution.
The first way, when you call
foo(0)
the substitution bring to
template <typename T, typename = void>
void foo (T const &)
{ std::cout << "is integral" << std::endl; }
template <typename T, typename>
void foo (T const &)
{ std::cout << "isn\'t integral" << std::endl; }
that is... you have two functions with the same signatures (a default template argument doesn't change the signature of a function) and a collision calling it.
In the second way you have only
template <typename T, int = 0>
void foo (T const &)
{ std::cout << "is integral" << std::endl; }
because the substitution failure in the second function make the function unusable and it's discarded. So you have only a function available and no collision.
Basically, I want to write code like that :
std::vector<float> a = { 54, 25, 32.5 };
std::vector<int> b = { 55, 65, 6 };
std::cout << a << b << std::string("lol");
It is not possible because there is no overload for operator<<(ostream&, vector)
So, I write a function that do the job :
template<template<typename...> typename T, typename ...Args>
std::enable_if_t<is_iterable_v<T<Args...>>>, std::ostream> &operator<<(std::ostream &out, T<Args...> const &t) {
for (auto const &e : t)
out << e << " ";
out << std::endl;
return out;
}
That works good, but I have a problem with string. Because strings are iterable and strings HAVE operator<< function.
So I tested with another trait like !is_streamable_out && _is_iterable testing something like that : std::declval<std::ostream&>() << std::declval<T>() and if it has begin / end functions. It works good on MSVC, but not on Clang (I think it is because the compiler use the function I just create as well, so it founds one overload available for all methods).
So, I am currently using !is_same_v<string, T> but it is not perfect IMHO.
Is there a way to know if a function exists without redeclaring the function?
Basically, I want to do something like that
if function foo does not exist for this type.
then function foo for this type is ...
It is not the same problem as Is it possible to write a template to check for a function's existence? because in this other thread, the function is not exactyly the same (toString vs toOptionalString). In my case, the function are the same.
Here is my full code :
template <class...>
struct make_void { using type = void; };
template <typename... T>
using void_t = typename make_void<T...>::type; // force SFINAE
namespace detail {
template<typename AlwaysVoid, template<typename...> typename Operator, typename ...Args>
struct _is_valid : std::false_type {};
template<template<typename...> typename Operator, typename ...Args>
struct _is_valid<void_t<Operator<Args...>>, Operator, Args...> : std::true_type { using type = Operator<Args...>; };
}
template<template<typename ...> typename Operator, typename ...Args>
using is_valid = detail::_is_valid<void, Operator, Args...>;
#define HAS_MEMBER(name, ...)\
template<typename T>\
using _has_##name = decltype(std::declval<T>().name(__VA_ARGS__));\
\
template<typename T>\
using has_##name = is_valid<_has_push_back, T>;\
\
template<typename T>\
constexpr bool has_##name##_v = has_##name<T>::value
HAS_MEMBER(push_back, std::declval<typename T::value_type>());
HAS_MEMBER(begin);
HAS_MEMBER(end);
template<typename T>
using is_iterable = std::conditional_t<has_begin_v<T> && has_end_v<T>, std::true_type, std::false_type>;
template<typename T>
constexpr bool is_iterable_v = is_iterable<T>::value;
template<class T, class Stream, class = void>
struct can_print : std::false_type {};
template<class T, class Stream>
struct can_print<T, Stream, void_t<decltype(std::declval<Stream&>() << std::declval<const T&>())>> : std::true_type {};
template<class T, class Stream = std::ostream>
constexpr bool can_print_v = can_print<T, Stream>::value;
template<typename T>
std::enable_if_t<is_iterable_v<T> && !can_print_v<T>, std::ostream> &operator<<(std::ostream &out, T const &t) {
for (auto const &e : t)
out << e << " ";
out << std::endl;
return out;
}
template<typename A, typename B>
std::ostream &operator<<(std::ostream &out, std::pair<A, B> const &p) {
out << p.first << " " << p.second << std::endl;
return out;
}
template<typename T>
std::enable_if_t<has_push_back_v<T>, T> &operator<<(T &c, typename T::value_type const &e) {
c.push_back(e);
return c;
}
and the main :
#include <iostream>
#include <vector>
#include "Tools/stream.h"
#include <string>
#include <map>
int main() {
std::vector<float> a = { 54, 25, 32.5 };
std::vector<int> b = { 55, 65, 6 };
std::cout << a;
std::cout << has_push_back<float>::value << " " << has_push_back<std::vector<float>>::value << std::endl;
std::cout << is_iterable<std::vector<float>>::value << " " << is_iterable<float>::value << std::endl;
getchar();
return 0;
}
How to avoid this sentence is false in a template SFINAE? provides an answer that solves your problem -- overload <<(ostream&, Ts...), which will be found with lower priority than any other << overload.
At the same time I'd say your plan is a poor one. Overloading operators for std types is a bad plan for 2 reasons.
First, you should be reluctant to overload operators for types you do not own unless there is a great reason.
Second, if you do so, you should do it in the namespace of the type, and you cannot inject your << into namespace std without making your program ill-formed.
Operators overloaded in a namespace different than the types in question can only be found in the namespace where you did the overload. Operators overloaded in a namespace related to the arguments can be found anywhere.
This results in fragile << that only works in one namespace.
So, instead, do this:
struct print_nothing_t {};
inline std::ostream& operator<<(std::ostream& os, print_nothing_t) {
return os;
}
template<class C, class Sep=print_nothing_t>
struct stream_range_t {
C&& c;
Sep s;
template<class T=print_nothing_t>
stream_range_t( C&& cin, T&& sin = {} ):
c(std::forward<C>(cin)),
s(std::forward<T>(sin))
{}
friend std::ostream& operator<<(std::ostream& os, stream_range_t&& self) {
bool first = true;
for (auto&& x:self.c) {
if (!first) os << self.s;
os << decltype(x)(x);
first = false;
}
return os;
}
};
template<class C, class Sep = print_nothing_t>
stream_range_t<C, Sep> stream_range( C&& c, Sep&& s={} ) {
return {std::forward<C>(c), std::forward<Sep>(s)};
}
Now, if you want nested vectors to work, you'd have to implement a stream range that applies an adapter to its contents.
Live example with this test code:
std::vector<int> v{1,2,3,4};
std::cout << stream_range(v, ',') << "\n";
output is 1,2,3,4.
How to make this recursive:
We can write a adapt_for_streaming function that dispatches to either identity (for things already streamable), and to stream_range for things iterable but not already streamable.
Users can then add new adapt_for_streaming overloads for other types.
stream_range_t then streams using adapt_for_streaming on its contents.
Next, we can add tuple/pair/array overloads to adapt_for_streaming and suddenly std::vector< std::vector< std::tuple<std::string, int> > > can be streamed.
End users can call stream_range directly, or adapt_for_streaming, to string an iterable container. You can even call stream_range directly on a std::string to treat it like a streamable collection of char instead of a string.
You could write a small detection idiom that tests if the expression stream << value is well formed*.
Here it is using std::ostream:
template<class...>
using void_t = void;
template<class T, class Stream, class=void>
struct can_print : std::false_type{};
template<class T, class Stream>
struct can_print<T, Stream, void_t<decltype(std::declval<Stream&>() << std::declval<const T&>())>> : std::true_type{};
template<class T, class Stream=std::ostream>
constexpr bool can_print_v = can_print<T, Stream>::value;
Now your can write your overload for operator<< like so:
template<template<class...> class C, class...T>
std::enable_if_t<!can_print_v<C<T...>>, std::ostream>& operator<<(std::ostream &out, C<T...> const &t) {
for (auto const &e : t)
out << e << " ";
out << std::endl;
return out;
}
and a test
std::vector<float> a = { 54, 25, 32.5 };
std::vector<int> b = { 55, 65, 6 };
std::cout << a;
std::cout << b;
std::cout << std::string("lol") << std::endl;
Demo
Yakk points out an interesting thing in their answer. This sentence is false.
Basically, by using !can_print_v to enable an overload for operator<<, the can_print_v should subsequently be true, but it's false because the first instantiation of the template resulted in the struct deriving from std::false_type. Subsequent tests for can_print_v are therefore invalid.
I'm leaving this answer as a cautionary tale. The trait itself is okay, but using it to SFINAE something that invalidates the trait is not okay.
*It appears OP has copied this code into their own codebase and then modified the question to include it, in case you were wondering why it looks the other way around
I've seen types that have corresponding to_string() function, but haven't overloaded operator<<(). So, when inserting to stream, one has to << to_string(x) which is verbose. I'm wondering whether it's possible to write a generic function that users operator<<() if supported and falls back to << to_string() if not.
SFINAE is overkill, use ADL.
The trick is to make sure that an operator<< is available, not necessarily the one supplied by the type definition:
namespace helper {
template<typename T> std::ostream& operator<<(std::ostream& os, T const& t)
{
return os << to_string(t);
}
}
using helper::operator<<;
std::cout << myFoo;
This trick is commonly used in generic code which needs to choose between std::swap<T> and a specialized Foo::swap(Foo::Bar&, Foo::Bar&).
Try
template <typename T>
void print_out(T t) {
print_out_impl(std::cout, t, 0);
}
template <typename OS, typename T>
void print_out_impl(OS& o, T t,
typename std::decay<decltype(
std::declval<OS&>() << std::declval<T>()
)>::type*) {
o << t;
}
template <typename OS, typename T>
void print_out_impl(OS& o, T t, ...) {
o << t.to_string();
}
LIVE
Yes, it is possible.
#include <iostream>
#include <sstream>
#include <string>
#include <type_traits>
struct streamy
{
};
std::ostream&
operator<<(std::ostream& os, const streamy& obj)
{
return os << "streamy [" << static_cast<const void *>(&obj) << "]";
}
struct stringy
{
};
std::string
to_string(const stringy& obj)
{
auto oss = std::ostringstream {};
oss << "stringy [" << static_cast<const void *>(&obj) << "]";
return oss.str();
}
template <typename T>
std::enable_if_t
<
std::is_same
<
std::string,
decltype(to_string(std::declval<const T&>()))
>::value,
std::ostream
>&
operator<<(std::ostream& os, const T& obj)
{
return os << to_string(obj);
}
int
main()
{
std::cout << streamy {} << '\n';
std::cout << stringy {} << '\n';
}
The generic operator<< will only be available if the expression to_string(obj) is well-typed for obj a const T& and has a result of type std::string. As you have already conjectured in your comment, this is indeed SFINAE at work. If the decltype expression is not well-formed, we will get a substitution failure and the overload will disappear.
However, this will likely get you into troubles with ambiguous overloads. At the very least, put your fallback operator<< into its own namespace and only drag it in locally via a using declaration when needed. I think you will be better off writing a named function that does the same thing.
namespace detail
{
enum class out_methods { directly, to_string, member_str, not_at_all };
template <out_methods> struct tag {};
template <typename T>
void
out(std::ostream& os, const T& arg, const tag<out_methods::directly>)
{
os << arg;
}
template <typename T>
void
out(std::ostream& os, const T& arg, const tag<out_methods::to_string>)
{
os << to_string(arg);
}
template <typename T>
void
out(std::ostream& os, const T& arg, const tag<out_methods::member_str>)
{
os << arg.str();
}
template <typename T>
void
out(std::ostream&, const T&, const tag<out_methods::not_at_all>)
{
// This function will never be called but we provide it anyway such that
// we get better error messages.
throw std::logic_error {};
}
template <typename T, typename = void>
struct can_directly : std::false_type {};
template <typename T>
struct can_directly
<
T,
decltype((void) (std::declval<std::ostream&>() << std::declval<const T&>()))
> : std::true_type {};
template <typename T, typename = void>
struct can_to_string : std::false_type {};
template <typename T>
struct can_to_string
<
T,
decltype((void) (std::declval<std::ostream&>() << to_string(std::declval<const T&>())))
> : std::true_type {};
template <typename T, typename = void>
struct can_member_str : std::false_type {};
template <typename T>
struct can_member_str
<
T,
decltype((void) (std::declval<std::ostream&>() << std::declval<const T&>().str()))
> : std::true_type {};
template <typename T>
constexpr out_methods
decide_how() noexcept
{
if (can_directly<T>::value)
return out_methods::directly;
else if (can_to_string<T>::value)
return out_methods::to_string;
else if (can_member_str<T>::value)
return out_methods::member_str;
else
return out_methods::not_at_all;
}
template <typename T>
void
out(std::ostream& os, const T& arg)
{
constexpr auto how = decide_how<T>();
static_assert(how != out_methods::not_at_all, "cannot format type");
out(os, arg, tag<how> {});
}
}
template <typename... Ts>
void
out(std::ostream& os, const Ts&... args)
{
const int dummy[] = {0, ((void) detail::out(os, args), 0)...};
(void) dummy;
}
Then use it like so.
int
main()
{
std::ostringstream nl {"\n"}; // has `str` member
out(std::cout, streamy {}, nl, stringy {}, '\n');
}
The function decide_how gives you full flexibility in deciding how to output a given type, even if there are multiple options available. It is also easy to extend. For example, some types have a str member function instead of an ADL find-able to_string free function. (Actually, I already did that.)
The function detail::out uses tag dispatching to select the appropriate output method.
The can_HOW predicates are implemented using the void_t trick which I find very elegant.
The variadic out function uses the “for each argument” trick, which I find even more elegant.
Note that the code is C++14 and will require an up-to-date compiler.
Based on the answer of #MSalters (credits goes to him), this one solves my problem and should make a complete answer.
#include <iostream>
#include <string>
#include <type_traits>
struct foo_t {};
std::string to_string(foo_t) {
return "foo_t";
}
template <class CharT, class Traits, class T>
typename std::enable_if<std::is_same<CharT, char>::value,
std::basic_ostream<CharT, Traits>&>::type
operator<<(std::basic_ostream<CharT, Traits>& os, const T& x) {
return os << to_string(x);
}
int main() {
std::cout << std::string{"123"} << std::endl;
std::cout << foo_t{} << std::endl;
}
Gathering the information from Using SFINAE to check for global operator<<? and templates, decltype and non-classtypes, I got the following code:
http://ideone.com/sEQc87
Basically I combined the code from both questions to call print function if it has ostream declaration, or to call the to_string method otherwise.
Taken from question 1
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> {
};
Taken from question 2
template <typename T>
typename std::enable_if<has_insertion_operator<T>::value, T>::type
print(T obj) {
std::cout << "from print()" << std::endl;
}
template <typename T>
typename std::enable_if<!has_insertion_operator<T>::value, T>::type
print(T obj) {
std::cout << obj.to_string() << std::endl;
}
Then my classes are like so:
struct Foo
{
public:
friend std::ostream& operator<<(std::ostream & os, Foo const& foo);
};
struct Bar
{
public:
std::string to_string() const
{
return "from to_string()";
}
};
And test output:
int main()
{
print<Foo>(Foo());
print<Bar>(Bar());
//print<Bar>(Foo()); doesn't compile
//print<Foo>(Bar()); doesn't compile
print(Foo());
print(Bar());
print(42);
print('a');
//print(std::string("Hi")); seg-fault
//print("Hey");
//print({1, 2, 3}); doesn't compile
return 0;
}
The print(std::string("Hi")); line seg-faults. Can anyone tell me why?
Both your functions print() are supposed to return something, but instead return nothing (unlike the versions in the Q&As you linked). This is undefined behavior per paragraph 6.6.3/2 of the C++11 Standard.
If print() is not supposed to return anything, let it return void, and put the SFINAE constraint in the template parameter list:
template <typename T,
typename std::enable_if<
has_insertion_operator<T>::value, T>::type* = nullptr>
void print(T obj) {
std::cout << "from print()" << std::endl;
}
template <typename T,
typename std::enable_if<
!has_insertion_operator<T>::value, T>::type* = nullptr>
void print(T obj) {
std::cout << obj.to_string() << std::endl;
}
Here is a live example containing the above change.
If you are working with C++03 and cannot specify default arguments for function template parameters, just avoid specifying a type as the second template argument to std::enable_if, or specify void:
template <typename T>
typename std::enable_if<has_insertion_operator<T>::value>::type
print(T obj) {
std::cout << "from print()" << std::endl;
}
template <typename T>
typename std::enable_if<!has_insertion_operator<T>::value>::type
print(T obj) {
std::cout << obj.to_string() << std::endl;
}