I have a template function in C++ that serializes an iterable:
template<typename Stream, typename Iter, typename Infix, typename Closure>
inline Stream &stream_iterable(Stream &os, Iter from, Iter to, Infix infix_, Closure open, Closure close) {
if (from == to) return os;
os << open << *from;
for (++from; from != to; ++from) {
os << infix_ << *from;
}
os << close;
return os;
}
For examaple, it basically converts std::vector<int>{1,2}
to a string "[1,2]"
I would like to check the type of the object the iterator is pointing to and if it is std::string
, I would like to use std::quoted
to add quotation around the elements of the vector, Something like this:
template<typename Stream, typename Iter, typename Infix, typename Closure>
inline Stream &steam_iterable_quoted(Stream &os, Iter from, Iter to, Infix infix_, Closure open, Closure close) {
if (from == to) return os;
os << open << std::quoted(*from);
for (++from; from != to; ++from) {
os << infix_ << std::quoted(*from);
}
os << close;
return os;
}
How can I check the type of (*from) and combine these two functions into one?
You don't actually need to know the type in the body of stream_iterable
. As the old saying goes, add a level of indirection:
namespace detail {
template<typename T>
constexpr T const& prepare_to_print(T const& t) { return t; }
auto prepare_to_print(std::string const s&) { return std::quoted(s); }
// A non-const overload would be required as well...
// Forwarding can be a drag sometimes
}
Just pass the dereferenced iterator to prepare_to_print
. The nice thing about overloads is that you can customize the behavior further by adding more of them later on.
This simplest, working version:
namespace quoting {
template<class T>
T const& auto_quote( T const& t ) { return t; }
template<class C, class T>
auto auto_quote( std::basic_string<C,T> const& s ) {
return std::quoted(s);
}
// add more std types that need quoting here.
}
now do this:
// ...
if (from == to) return os;
using quoting::auto_quote;
os << open << auto_quote(*from);
for (++from; from != to; ++from) {
os << infix_ << auto_quote(*from);
}
os << close;
// ...
in order to make something be quoted differently, override auto_quote
in the namespace of the type (if not in std
; no injecting names into std
allowed) or in namespace quoting
. It will be picked up automatically.
So if you have your my_string
in namespace my_ns
:
namespace my_ns {
auto auto_quote( my_string const& s ) {
// some manual quoting code
}
}
and it will be picked up automatically by the above code.
You can use decltype(*from)
to obtain the result type of the dereference operator, but (1) it may need to be further massaged before doing comparisons (it may be a reference, a value, possibly cv-qualified, ...), and (2) it's not really extensible WRT other types.
In general for this kind of stuff you want to delegate to a template function that (in your case) is responsible to actually output the datum on the stream, with a default for the "normal" types, and specialize it for types that require special treatment.
Use this to retrieve type of object referenced by an iterator: std::iterator_triats<SomeIteratorType>::value_type
To combine these two functions you can use constexpr if statement which is a C++17 feature.
The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.