c++templatesvisual-c++compiler-bug

MSVC bug? Template friend function cannot access private members despite template friend declaration


I have the following C++ code:

template<typename T>
class Foo;

template<typename T, typename U>
Foo<T> operator+(Foo<T> lhs, const Foo<U>& rhs);

template<typename T>
class Foo {
    template<typename>
    friend class Foo;

    T inner;

public:
    Foo(T i) : inner(i) {}

    template<typename U>
    friend Foo<T> operator+(Foo<T> lhs, const Foo<U>& rhs) {
        lhs.inner += rhs.inner;
        return lhs;
    }
};

int main() {
    Foo<int> a = 4;
    Foo<unsigned> b = 5;
    Foo<int> c = a + b;
}

godbolt

It compiles fine with GCC and clang, but compilation fails with an error in MSVC v19.37 and in Visual Studio 2015:

example.cpp
<source>(19): error C2248: 'Foo<unsigned int>::inner': cannot access private member declared in class 'Foo<unsigned int>'
<source>(12): note: see declaration of 'Foo<unsigned int>::inner'
<source>(26): note: see declaration of 'Foo<unsigned int>'
<source>(27): note: see reference to function template instantiation 'Foo<int> operator +<unsigned int>(Foo<int>,const Foo<unsigned int> &)' being compiled
<source>(27): note: see the first reference to 'operator +' in 'main'
Compiler returned: 2

This seems to be some kind of issue with MSVC. Is there a workaround? Or is there something else I'm missing?


Solution

  • The best solution I've found is to move the actual implementation into a static method, and call that static method inside the friend function:

    template<typename T>
    class Foo {
        template<typename>
        friend class Foo;
    
        T inner;
    
        template<typename U>
        static Foo op_add(Foo lhs, const Foo<U>& rhs) {
            lhs.inner += rhs.inner;
            return lhs;
        }
    
    public:
        Foo(T i) : inner(i) {}
    
        template<typename U>
        friend Foo operator+(Foo lhs, const Foo<U>& rhs) {
            return op_add(lhs, rhs);
        }
    };
    

    godbolt