I'm trying to make a simple template function that given some parameters, it outputs them with a space in between. Some of those can be elements of an enum, and in that case I want to output its integer value.
This is the code I have:
#include <iostream>
#include <type_traits>
using std::cerr;
using std::endl;
// Output integer value if parameter is an element of an enum
template<typename T, typename = typename std::enable_if_t<std::is_enum<T>::value>>
constexpr std::ostream& debug(const T& a) {
cerr << (int)(a);
return cerr;
}
// Output parameter otherwise
template<typename T, typename = typename std::enable_if_t<!std::is_enum<T>::value>>
constexpr std::ostream& debug(const T& a) {
cerr << a;
return cerr;
}
// Print parameters separated by a space
template<typename T, typename ...U>
constexpr std::ostream& debug(const T& a, const U&... b) {
debug(a) << ' ';
debug(b...);
return cerr;
}
template<typename ...U>
constexpr void debug(const U&... a) {
debug(a...) << std::endl;
}
enum class Animal{Dog, Cat};
int main() {
debug(Animal::Dog);
debug(Animal::Dog, Animal::Cat);
debug("Hello");
debug(100, 'A');
debug(Animal::Dog, "Hello", "Bye");
}
Commenting the last three lines it says that the second function is a redeclaration of the first. Any ideas on how to solve this or why it does not work?
Default template arguments are not part of the function definition. Use a dummy parameter instead, so that the second argument has a different type:
template<typename T, typename std::enable_if_t<std::is_enum<T>::value, int> = 0>
constexpr std::ostream& debug(const T& a) {
std::cerr << (int)(a);
return std::cerr;
}
template<typename T, typename std::enable_if_t<!std::is_enum<T>::value, int> = 0>
constexpr std::ostream& debug(const T& a) {
std::cerr << a;
return std::cerr;
}
Related
I have a pretty specific situation where I'm feeding a bunch of data to a hasher-like class. In particular, one data type that I use has a member whose type depends on the supertype's type parameter. Long story short, here's a piece of code that illustrates this behaviour :
#include <assert.h>
#include <iostream>
#include <string>
#include <type_traits>
#include <utility>
#include <vector>
// Some dummy priority structs to select overloads
struct priority0 { };
struct priority1 : priority0 { };
// This is the hasher-like function
struct Catcher
{
// Ideally we feed everything to this object through here
template <typename T> Catcher& operator<<(const T& v)
{
add(v, priority1{}); // always attempt to call the highest-priority overload
return *this;
}
// For floating-point data types
template <typename T> auto add(const T& v, priority1) -> std::enable_if_t<std::is_floating_point_v<T>, void>
{
std::cout << "caught float/double : " << v << std::endl;
}
// For ranges
template <class T> auto add(const T& range, priority1) -> decltype(begin(range), end(range), void())
{
for(auto const& v : range)
*this << v;
}
// For chars
void add(char c, priority1)
{
std::cout << c;
std::cout.flush();
}
// When everything else fails ; ideally should never happen
template <typename T> void add(const T& v, priority0)
{
assert(false && "should never happen");
}
};
// The one data type. Notice how the primary template and the
// specialization have a `range` member of different types
template <class T> struct ValueOrRange
{
struct Range
{
T min;
T max;
};
Range range;
T value;
};
template <> struct ValueOrRange<std::string>
{
std::vector<std::string> range;
std::string value;
};
// Overload operator<< for Catcher outside of the
// class to allow for processing of the new data type
// Also overload that for `ValueOrRange<T>::Range`. SFINAE should make sure
// that this behaves correctly (?)
template <class T> Catcher& operator<<(Catcher& c, const typename ValueOrRange<T>::Range& r)
{
return c << r.min << r.max;
}
template <class T> Catcher& operator<<(Catcher& c, const ValueOrRange<T>& v)
{
return c << v.range << v.value;
}
int main(int argc, char *argv[])
{
ValueOrRange<std::string> vor1{{}, "bleh"};
ValueOrRange<float> vor2{{0.f, 1.f}, 0.5f};
Catcher c;
c << vor1; // works fine, displays "bleh"
c << vor2; // fails the assert in Catcher::add(const T&, priority0) with T = ValueOrRange<float>::Range
return 0;
}
While the line c << vor1 gets resolved correctly through the various overloads and has the intended effect, the second line c << vor2 fails the assert.
What I want to happen : c << vor2 calls Catcher& operator<<(Catcher& s, const ValueOrRange<float>& v), which in turn calls Catcher& operator<<(Catcher& s, const typename ValueOrRange<float>::Range& r)
What does happen : instead of Catcher& operator<<(Catcher& s, const typename ValueOrRange<float>::Range& r), it is Catcher& Catcher::operator<<(const T& v) with T = typename ValueOrRange<float>::Range that is called, and thus the assert fails.
Worthy of note is that this same code has the intended effect on MSVC, and fails the assert on GCC.
Any idea on how I should fix that ?
Thanks to feedback from Igor Tandetnik, I got rid of the ::Range-specific overload and simply went for checking std::is_same_v<T, std::string>. A little less modular than I'd like, but it'll do the trick.
// A single function will do the trick
template <class T> Catcher& operator<<(Catcher& c, const ValueOrRange<T>& v)
{
if constexpr (std::is_same_v<T, std::string>)
c << v.range;
else
c << v.range.min << v.range.max;
return c << v.value;
}
In Catcher& operator<<(Catcher& c, const typename ValueOrRange<T>::Range& r), T in non deducible.
One work around would be friend function:
template <class T> struct ValueOrRange
{
struct Range
{
T min;
T max;
friend Catcher& operator<<(Catcher& c, const Range& r)
{
return c << r.min << r.max;
}
};
Range range;
T value;
};
Demo
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.
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;
}
I have a set of templates/functions that allow me to print a tuple/pair assuming that each type in the tuple/pair has operator<< defined for it. Unfortunately, due to 17.4.3.1, it is illegal to add my operator<< overloads to std. Is there another way to get ADL to find my operator<<? If not, is there any actual harm in wrapping my overload in namespace std{}?
The code for anyone interested: (I'm using gcc-4.5)
namespace tuples {
using ::std::tuple;
using ::std::make_tuple;
using ::std::get;
namespace detail {
template< typename...args >
size_t size( tuple<args...> const& )
{
return sizeof...(args);
};
template<size_t N>
struct for_each_ri_impl
{
template<typename Func, typename Tuple>
void operator()(Func func, Tuple const& arg)
{
for_each_ri_impl<N-1>()(func, arg );
func( get<N>( arg ), size(arg) - N - 1 );
}
};
template<>
struct for_each_ri_impl<0>
{
template<typename Func, typename Tuple>
void operator()(Func func, Tuple const& arg)
{
func( get<0>( arg ), size(arg) - 1 );
}
};
}//detail
template<typename Func, typename ... Args>
void for_each_ri( tuple<Args...>const& tup, Func func )
{
detail::for_each_ri_impl< sizeof...(Args)-1>()( func, tup );
}
struct printer {
std::ostream& out;
const std::string& str;
explicit printer( std::ostream& out=std::cout, std::string const& str="," ) : out(out), str(str) { }
template<typename T>void operator()(T const&t, size_t i=-1) const { out<<t; if(i) out<<str; }
};
//Should this next line go into namespace std? Is there another way?
template<typename ... Args>
std::ostream& operator<<(std::ostream& out, std::tuple< Args... > const& tup)
{
out << '[';
tuples::for_each_ri( tup, tuples::printer(out,", ") );
return out << ']';
}
} //tuples
//Edits --
int main()
{
using namespace std;
cout<<make_tuple(1,'a',"Hello")<<endl;
return 0;
}
Compiling the above yields:
test.cpp: In function 'int main()':
test.cpp:69:31: error: cannot bind 'std::ostream' lvalue to 'std::basic_ostream&&' > /opt/local/include/gcc45/c++/ostream:579:5: error: initializing argument 1 of 'std::basic_ostream<_CharT, _Traits>& std::operator<<(std::basic_ostream<_CharT, _Traits>&&, const _Tp&) [with _CharT = char, _Traits = std::char_traits, _Tp = std::tuple]'
Put your own light wrapper class around it and then overload operator<< to use that. However beware that even if your light wrapper has an implicit constructor you will probably still need to use it explicitly when you pass it to operator<<
template< typename ...VA_ARGS >
struct format_tuple
{
typedef tuple<VA_ARGS...> tuple_type;
// any format variables
const tuple_type & tup;
format_tuple( const tuple_type& t): tup(t) {}
};
template< typename ...VA_ARGS > format_tuple<VA_ARGS...> makeFormatTuple( const tuple<VA_ARGS...> & t )
{
return format_tuple( t );
}
template<typename ...VA_ARGS>
std::ostream& operator<<( std::ostream& os, const format_tuple<VA_ARGS...> & ft )
{
// original implementation
}
This is an outline as I'm not sure exactly how to do it with variadic templates although it should be possible. You can easily implement several versions though with 1, 2, 3, etc.parameters, eg:
template<typename T1, typename T2, typename T3>
class format_tuple_3; //etc
template<typename T1, typename T2, typename T3>
format_tuple_3<T1, T2, T3> makeFormatTuple( tuple<T1,T2,T3> const&); //etc
The harm is someone else (such as in a third party library you want to use) also adding these declarations to std. Even if theirs behave identically, you'll violate the ODR.
Just put these in your project's namespace:
namespace kitsune_ymg {
// Op<< overloads here.
// Your "normal" stuff.
void normal_stuff() {
std::cout << std::pair<int, int>(42, 3);
}
And then anything in your project can use them.
I'm still not sure exactly why this doesn't work for you, but it seems you want something like:
namespace kitsune_ymg {
namespace tuples {
// Op<< overloads here.
}
using namespace tuples;
// Your "normal" stuff.
}
namespace completely_separate_project {
using kitsune_ymg::tuples;
// Now you can use those op<< overloads in this scope, too.
void perfectly_normal_beast() {
std::cout << std::pair<int, int>(42, 3);
}
}
You mustn't add your own operator<< to std. However, you can write an adapter for tuples, or one for streams, and use that, with a minimal amount of change to the call sites.
I'll assume C++17 or newer (to use structured bindings and fold expressions), although the question is obviously much older.
Adapt the tuple
#include <ostream>
#include <tuple>
template<typename... Args>
struct printable_tuple
{
typedef std::tuple<Args...> tuple_type;
const tuple_type& t;
// implicit converting constructor
printable_tuple(const tuple_type& t)
: t(t)
{}
};
template<typename... Args>
std::ostream& operator<<(std::ostream& os, const printable_tuple<Args...>& tuple)
{
const char *sep = "";
os << '[';
std::apply([&os,&sep](auto&&...args){((os << sep << args, sep = ","),...);}, tuple.t);
return os << ']';
}
#include <iostream>
int main()
{
std::cout << format_tuple{std::tuple{1,'a',"Hello"}} << '\n';
}
This is the least intrusive, as we can use the returned stream normally (if (os << tuple), for instance), but it requires wrapping each and every argument.
Adapt the stream
#include <tuple>
template<typename Stream>
class tuple_ostream
{
Stream& os;
public:
// conversions from and to Stream
tuple_ostream(Stream& os) : os{os} {}
operator Stream&() const { return os; };
// generic forwarding <<
template<typename T>
tuple_ostream& operator<<(const T&t)
{
os << t;
return *this;
}
// overload for tuples
template<typename... Args>
tuple_ostream& operator<<(const std::tuple<Args...>&t)
{
const char *sep = "";
os << '[';
std::apply([this,&sep](auto&&...args){((os << sep << args, sep = ","),...);}, t);
os << ']';
return *this;
}
};
#include <iostream>
int main()
{
tuple_ostream{std::cout} << std::tuple{1,'a',"Hello"} << '\n';
}
Adapting the stream is obviously simpler when we need to write several tuples to the same stream, but we can no longer directly use the returned stream as the original unless we add more functions to the wrapper.
Hat-tip to CashCow's answer for a starting point for this one.