在类模板
A
中,A
的不同实例已成为好友。具体来说,A<T>
和A<T const>
彼此成为朋友(见下文)。这并不意味着 A<T>
的朋友应该能够访问 A<T const>
的私有成员,反之亦然。但显然 gcc 和 clang 接受了这一点。
#include <type_traits>
template <typename T>
struct A {
private:
T value{};
public:
using InvT = std::conditional_t<std::is_const_v<T>, std::remove_const_t<T>, std::add_const_t<T>>;
friend A<InvT>;
friend bool operator==(A const& a, A<InvT> const& b) noexcept {
return a.value == b.value;
// ^^^^^ private. should not be accessible
}
};
他们接受这一点是错误的吗?
当
operator==
移动到类定义之外时,所有三个主要编译器(GCC、CLANG、MSVC)都接受此代码,即使friend A<InvT>
声明被删除!请参阅https://godbolt.org/z/YP1sKKh1f
#include <type_traits>
template <typename T>
struct A;
template <typename T, typename InvT>
bool operator==(A<T> const& a, A<InvT> const& b) noexcept {
return a.value == b.value;
}
template <typename T>
struct A {
private:
T value{};
public:
using InvT = std::conditional_t<std::is_const_v<T>, std::remove_const_t<T>, std::add_const_t<T>>;
friend bool operator==(A<T> const& a, A<InvT> const& b) noexcept;
};
int main() {
A<int> a;
A<int const> b;
(void)(a == b);
}
对于上面的代码,GCC 警告说,
friend operator==
声明实际上是错误的,因为它不是声明模板,而是声明一个自由函数/运算符。更正的是在 <>
之后添加一个空模板规范 operator==
:
friend bool operator==<>(A<T> const& a, A<InvT> const& b) noexcept;
通过此更新,所有编译器都正确拒绝编译代码,因为禁止访问私有
b.value
:https://godbolt.org/z/7j1zGeEs9