2

I have the following operator<<() overload for my class with C++17 folds:

template <typename... Args>
ostream& operator <<(Args&&... args)
{
    //Currently:
    return (m_osCout << ... << args);

    //What I need:
    IF ANY OF THE parameters in args "was" of type, say TSeek,  
    which can be a manipulator function etc,  then AFTER finishing 
    with the parameter pack, I would like to do some further operation
    , for instance, restore the state of m_osCount
 }

Is it possible what I need as described above? Any partial responses to set some directions would be appreciated...

Despite I coined the question as if I was asking for an automated stream flag restorer, please note that I am after the general solution, not particularly restoring std::cout or o/istream object restoration. In practice my class is a kind of mathematical object that accepts custom-types as operator arguments, some of which requires ostream's manipulators-like functions but it is generally very very inconvenient to require user to supply some finalizing operands before starting a next such usage.

One idea that came to me was to return a different kind of temporary object of a new smart type whenever TSeek was provided in args... list, so that after the last argument is forwarded to it, it will be destructed automatically and this really is the time that I want to do my finalizing task!

Should I proceed like this or...?

max66
  • 65,235
  • 10
  • 71
  • 111
mami
  • 109
  • 1
  • 7
  • For starters, an `<<` overload will always have exactly one parameter. What you need to do is even simpler than you think. You will always have exactly one parameter. A parameter pack, here, accomplishes absolutely nothing useful, whatsoever. – Sam Varshavchik Jan 10 '19 at 23:46
  • That's right! I should have used a member function instead of operator<<() – mami Jan 11 '19 at 00:23

1 Answers1

2

Well... as far I know, a stream operator<<() must receive exactly two arguments.

So you can't define a variadic operator<<().

If you accept a generic template variadic function, foo() by example, if you can use C++17 isn't really difficult.

To check the presence of a type TSeek in Args... pack, you can write something as

constexpr bool withTSeek { (std::is_same<Args, TSeek>{} || ...) };

The following is a full compiling example

#include <iostream>
#include <utility>
#include <type_traits>

struct TSeek
 { };

std::ostream & operator<< (std::ostream & o, TSeek const &)
 { return o << " [TSeek!] "; }

template <typename ... Args>
std::ostream & foo (std::ostream & o, Args && ... args)
 {
   constexpr bool withTSeek { (std::is_same<Args, TSeek>{} || ...) };

   (o << ... << args);

   if ( withTSeek )
      o << " --- TSeek detected" << std::endl;
   else 
      o << " --- TSeek NOT detected" << std::endl;

   return o;
 }

int main ()
 {
   foo(std::cout, 1, 2, TSeek{}, 5, 7);
   foo(std::cout, 11, 13, 17, 19, 23);
 }
max66
  • 65,235
  • 10
  • 71
  • 111
  • How simple it was! Many thanks! Exact solution for my specific problem even if i might have implied something different in my question body... Despite ostream was just for problem-statement purposes only, then can't we use this approach to restore ostream flag states only by extending your solution to detect manipulator functions? Idea is that if if withTSeek_Manipulator is true, first save the flags, do streaming and check flag again to restore it... – mami Jan 10 '19 at 23:47
  • @mami: This is doable, but it will require a type-trait to detect whether it's a stream manipulator. This should be similar to the way the `withTSeek` is written -- except for your case you should be able to base it on whether the argument is invocable with an `ostream`. You might be able to use something like `(std::is_invocable{} || ...)` to detect this. Then in C++17 you can use `static if` to create compile-time scopes that only expand if the expression resolves `true` -- which gives you your two cases: with and without manipulators. – Human-Compiler Jan 11 '19 at 13:57