c++templatesclangfriend

clang bug? Ambiguous function call compilation errors, yet there is no amiguity present


I have been bashing my head in for the past 9 hours.

I just got a new MacBookPro with the M3 processor (ARM), and installed all command-line tools, including clang, with xcode-select --install.

clang++ is mistaking a friend declaration within a class and its definition outside the class as two distinct functions, despite having identical signatures.

I have reduced my problematic code as much as humanly possible to expose the cause of the compilation errors. I am sure this means clang is faulty, as I've been writing C++ for a while and have never run into this - the code also compiles fine on my other Macs and Linux instance.

I deleted and reinstalled all the command-line tools. Same stuff.

Here is the bare-bones code:

#include <iostream>

namespace gml {
    template <typename T>
    concept Numeric = requires (T value) {
        T{};
        // lots of stuff...
    };
    template <Numeric T>
    class tensor {
        // lots more stuff...
    public:
        tensor() = default; // constructs an empty tensor
        template <Numeric U, Numeric V>
        friend bool operator==(const tensor<U>&, const tensor<V>&);
    };
    template <Numeric U, Numeric V>
    bool operator==(const tensor<U>& t1, const tensor<V>& t2) {
        return true;
    }
}

int main() {
    gml::tensor<long double> t;
    gml::tensor<long double> t3;
    std::cout << std::boolalpha << "t == t3: " << (t == t3) << std::endl;
    return 0;
}

... and here is the exact compilation error I get from the above:

test.cpp:26:54: error: use of overloaded operator '==' is ambiguous (with operand types 'gml::tensor<long double>' and 'gml::tensor<long double>')
    std::cout << std::boolalpha << "t == t3: " << (t == t3) << std::endl;
                                                   ~ ^  ~~
test.cpp:15:21: note: candidate function [with U = long double, V = long double]
        friend bool operator==(const tensor<U>&, const tensor<V>&);
                    ^
test.cpp:18:10: note: candidate function [with U = long double, V = long double]
    bool operator==(const tensor<U> &t1, const tensor<V> &t2) {
         ^
1 error generated.

I would most appreciate it if someone could give me some insight on this.

P.S., I compiled using clang++ -std=c++20 test.cpp -o test, and running clang++ --version prints:

Apple clang version 15.0.0 (clang-1500.1.0.2.5)
Target: arm64-apple-darwin23.3.0
Thread model: posix
InstalledDir: /Library/Developer/CommandLineTools/usr/bin

Solution

  • This seems to be a apple-clang bug and the program is well-formed. All three other compilers(gcc, clang and msvc) compiles the program just fine.

    As a workaround for apple-clang, you can just define the friend template inside the class template:

    namespace gml {
        template <Numeric T>
        class tensor {
            
        public:
            //other code as before
            template <Numeric U, Numeric V>
            friend bool operator==(const tensor<U>&, const tensor<V>&) //provide definition here inside class
            {
                return true;  
            }
        };
        
    }