简体   繁体   中英

How to determine the type of the object an iterator is pointing to in c++ template function?

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.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM