Search code examples
c++visual-c++namespacesoperator-overloadingfriend

C++ How to implement friend operator overload defined in a namespace?


This class should use cout to print.

header

#pragma once
#ifndef Operator_Overload_h
#define Operator_Overload_h
#include <iostream>
namespace OperatorOverload {
    class CustomType {
    public:
        int value;
        friend const bool operator<(const CustomType&, const CustomType&);
        friend std::ostream& operator<<(std::ostream&, const CustomType&);
    };
}
#endif

cpp

#include "OperatorOverload.h"
using namespace OperatorOverload;
using namespace std;


const bool OperatorOverload::operator<(const CustomType& left, const CustomType& right) {
    return left.value < right.value;
}

ostream& OperatorOverload::operator<<(ostream& os, const CustomType& c) {
    os << c.value;
    return os;
}

int main()
{
    CustomType ct1, ct2;
    ct1.value = 1;
    ct2.value = 2;
    std::cout << "ct1 < ct2 = " << (ct1 < ct2) << "\n";
    std::cout << ct1 << "\n";
}

Error

Error C2039 '<<': is not a member of 'OperatorOverload'

Error C2593 'operator <<' is ambiguous

But operator< works. and if I replace operator<< with:

namespace OperatorOverload {
    ostream& operator<<(ostream& os, const CustomType& c) {
        os << c.value;
        return os;
    }
}

It's working. But I don't know exactly how this happens.

Why does operator < work, but operator << doesn't?

What am I doing wrong?


Solution

  • This seems to be a bug specific to Visual Studio 2019 16.11 (MSVC 19.29) in conformance mode (/permissive- or /std:c++20//std:c++latest).

    In all other (prior or later) versions I tested and in non-conformance mode, the code compiles fine.

    I don't see anything wrong with your code. It is not allowed to use a qualified name to declare a new function into a namespace. But you are trying to define a function that has already been declared in the namespace. That should be fine, even if the function is not visible to usual lookup (at least this seems quite clear to me in the current standard draft). The compiler should accept it.

    The workaround you suggest at the end of your question is however the more common approach to defining friend functions anyway.