3

I've been trying to use a templated adapter to enable use with an overloaded operator. I'm getting a compile error (gcc 4.5.2) that seems a contradiction to me. I'd like to know why and how to get around it. Below is simplified code that illustrates the problem.

// The adapter
template <typename T>
class A {
    T t;
public:
    A(T t_) : t(t_) {}
};

// Utility function to return an adaptor
template <typename T>
A<T> make_A(T t) {
    A<T> a(t);
    return a;
}

// The operator overload on the adapter
template <typename T>
A<T> &operator<<(A<T> &a, int) {
    return a;
}

// Shows use case
int main(int,char**) {
    auto aa = make_A(1);
    aa << 2;        // Compiles

    // Desired use:
    make_A(4) << 5; // Compile Error
}

The error messages:

main_operatorinsert.cpp: In function ‘int main(int, char**)’:
main_operatorinsert.cpp:28:22: error: no match for ‘operator<<’ in ‘make_A [with T = int](4) << 5’
main_operatorinsert.cpp:18:11: note: candidate is: A<T>& operator<<(A<T>&, int) [with T = int]

Why does the line "aa << 2;" compile, where the line "make_A(4) << 5;" does not? make_A returns the same type as aa. Why is the compiler getting a mismatch? How can I get around this?

walrii
  • 3,472
  • 2
  • 28
  • 47

2 Answers2

3

make_A returns an rvalue, but your operator<< requires a non-const lvalue as the first argument. You need to redesign a bit around this, if you really need to support make_A(4) << 5; you could make operator<< a member function, but beware that returning an lvalue reference from it is dangerous.

David Rodríguez - dribeas
  • 204,818
  • 23
  • 294
  • 489
2

You can't bind a temporary (make_A(4)) to a non-const lvalue reference.

You could try making it a const reference, or just avoid the temporary. In C++11 you can use rvalue references.

See: How come a non-const reference cannot bind to a temporary object?

Community
  • 1
  • 1
Pubby
  • 51,882
  • 13
  • 139
  • 180