c++ overload generic method, by-reference and by-value

Viewed 86

I have two generic methods (edit: actually operators but the issue is the same for methods) that are identical, except from that one uses its formal parameter by reference and the other method uses its formal parameter by value.

struct shout_t {
    template<typename T>
    shout_t& operator<<(T &x) { cout << x; return *this; } // by reference
    
    template<typename T>
    shout_t& operator<<(T x) { cout << x; return *this; } // by value
};

The intention of the "by-reference" method is to allow "large" objects to be used without copying. The "by-value" method is aimed at literals.

Since the "by-value" method can handle both cases (objects per se and literals), this gives an error:

int main() { // Here "large object" ~ string, "literal" ~ int
    shout_t shout;
    shout << 42; // OK
    shout << "FTL"; // ERROR: Overloaded operator '<<' is ambiguous
}

The behaviour I was looking for is try first if "by-reference" method applies, if not, apply "by-value" method.

How to resolve this? How to obtain the intended behaviour of two methods that are identical except from their "by-value" and "by-reference" signature?

1 Answers

There are two scenarios here, either you might want to change the object passed as a parameter, or you don't. In the latter case, pass as const-qualified reference:

struct shout_t {
    template<typename T>
    shout_t& operator<<(const T &item) { cout << item; return *this; }
};

and otherwise, use a forwarding reference in conjuction with std::forward:

struct shout_t {
    template<typename T>
    shout_t& operator<<(T&& item) { cout << std::forward<T>(item); return *this; }
};
Related