c++ MSVC bug?尽管声明了模板友元,但模板友元函数无法访问私有成员

jv4diomz  于 2023-10-20  发布在  其他
关注(0)|答案(1)|浏览(113)

下面是C++代码:

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
它使用GCC和clang编译得很好,但在MSVC v19.37和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

这似乎是MSVC的一个问题。是否有变通办法?还是我还漏掉了什么

hivapdat

hivapdat1#

您的示例代码有两个问题。
1.你在friend函数上使用了Foo模板参数。这会影响编译器如何看待这个声明,并混淆编译器(这就是为什么我删除了我的答案的第一个版本)。朋友功能不应该依赖于T
1.在声明友谊的地方定义函数在所有编译器上都是错误的,即使没有使用泛型编程。所以我建议你避免这种情况,作为一个经验法则。
如果你用自己的模板参数和Foo类模板的作用域之外来定义函数模板,它就不会有讨厌的黑客攻击。

template<typename T>
class Foo {
    T inner;

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

    T get() const {
        return inner;
    }

    template<typename W, typename U>
    friend auto operator+(Foo<W> lhs, const Foo<U>& rhs) -> Foo<W>;
};

https://godbolt.org/z/K8e3dKf4v
请注意,我从你的例子中删除了一些噪音代码。

相关问题