1

I have the following code...

#include <sstream>

enum class eTag
{
    A,
    B,
    C
};

template<eTag I> std::ostream& operator<< (std::ostream& str, int i)
{
    return str;  // do nothing
}

template<> std::ostream& operator<< <eTag::A>(std::ostream& str, int i)
{
    return str << "A:" << i;  // specialize for eTag::A
}

template<> std::ostream& operator<< <eTag::B>(std::ostream& str, int i)
{
    return str << "B:" << i;  // specialize for eTag::B
}

template<> std::ostream& operator<< <eTag::C>(std::ostream& str, int i)
{
    return str << "C:" << i;  // specialize for eTag::C
}

int main()
{
    std::ostringstream s;

    // s << <eTag::A>(42) << std::endl;

    return 0;
}

This compiles. But as you can see from the commented line in main(), I'm struggling with how to actually invoke a specialization of the ostream operator.

user1715664
  • 153
  • 2
  • 10
  • possible duplicate of [Is it not possible to call C++ operators manually?](http://stackoverflow.com/questions/7225962/is-it-not-possible-to-call-c-operators-manually) – Pradhan Mar 30 '15 at 21:22
  • 1
    Though hideous, `operator << (std::cout, 42) << std::endl;`. I'm more curious *why* you would want to do this. ` – WhozCraig Mar 30 '15 at 21:24
  • 1
    @Pradhan not really a dupe, right? As the question you linked talks mostly about overloading the `operator+` for fundamental types. – vsoftco Mar 30 '15 at 21:30
  • Your operator takes two arguments. You gave it one. Seems clear to me! – Lightness Races in Orbit Mar 30 '15 at 21:31

2 Answers2

1

Quick answer:

operator<< <eTag::A>(std::cout,42);

I think you're much better off with implementing your own template-class manipulator that friends ostream& operator<<(ostream&), and keeps the state as a member variable (initialized via a constructor). See here (except for the template-part)

Community
  • 1
  • 1
vsoftco
  • 55,410
  • 12
  • 139
  • 252
1
operator<<<eTag::A>(std::cout, 42) << std::endl;

(You can add a space between operator<< and the template argument list if you want. Doesn't make a difference.)

This is pretty nasty. Usually we don't write operators that require explicit template arguments. Better to do something like this:

inline std::ostream& operator<<(std::ostream& os, eTag x) {
    if (x == eTag::A) {
        return os << "A:";
    } else if (x == eTag::B) {
        return os << "B:";
    } else if (x == eTag::C) {
        return os << "C:";
    } else {
        throw std::range_error("Out of range value for eTag");
    }
}

Then:

std::cout << eTag::A << 42 << std::endl;

A good compiler will be able to inline this, so your code will be as efficient as if you had just typed

std::cout << "A:" << 42 << std::endl;
Brian Bi
  • 111,498
  • 10
  • 176
  • 312
  • nice, the only issue I see here is the fact that the `throw` will never execute. If you pass anything else than a tag, then the `std` `operator<<` kicks in. I see, it can happen if you have a larger `enum`... – vsoftco Mar 30 '15 at 21:42
  • @vsoftco You can think of it as a guard in case someone adds more tags to the enum and forgets to update the `operator<<`. – Brian Bi Mar 30 '15 at 21:51