这让我在过去几个小时里疯狂,我似乎无法解决这个问题。我已将问题提炼到这60行代码(包括主函数)。
#include <iostream>
namespace n1 {
// the general definition
template <class X, class Y> void f(X&, const Y&)
{
std::cout << "general template definition.\n";
}
} // namespace n1
namespace n2 {
// CRTP
template <class Derived> class A
{
int data;
// partial function template specialization for n1::f, and declare
// it a friend too, so that it may access the data attribute of A
template <class Y> friend void n1::f(A<Derived>& a, const Y& y);
}; // class A
} // namespace n2
namespace n1 {
// implementation for this particular function template specialization
template <class Derived, class Y> void f(n2::A<Derived>& a, const Y& y)
{
std::cout << "partial template specialization: " << a.data << "\n";
}
} // namespace n1
namespace n2 {
// Another class!
class B : public A<B>
{
}; // class B
} // namespace n2
namespace n1 {
// --------------------
// tricky part is here!
// --------------------
template <class Y> void f(n2::B& b, const Y& y)
{
// FAIL! not a friend! How?
f(static_cast<n2::A<n2::B>&>(b), y);
}
} // namespace n1
int main()
{
n2::B b;
int x;
n1::f(b, x); // should print "partial template specialization"
return 0;
}
那么,我想要的&#34;是使用n1::f
的具体子类调用时,编译器选择A<Derived>
的函数模板特化。为了确保编译器支持我的专业化,我需要为每个子类(在本例中为B
)提供简单地委托调用的n1::f
模板特化。发生这种情况时,我希望data
的{{1}}成员变量可供A<Derived>
访问,因为我声明n1::f
是n1::f
的朋友。但是,GCC抱怨A<Derived>
是私有且无法访问的see this snippet on Coliru。
这种结构是否可行?如果是这样,我怎么能绕过编译器抱怨A<Derived>::data
无法访问? (公开宣传不是一种选择)。
答案 0 :(得分:3)
您的班级定义必须如下所示:
template <class Derived> class A
{
int data;
template <class D, class Y> friend void n1::f(A<D>& a, const Y& y);
};
实际上,函数声明是:
template <class Derived, class Y> void f(n2::A<Derived>& a, const Y& y)
虽然您的朋友声明是:
template <class Y> friend void n1::f(A<Derived>& a, const Y& y);
在这种情况下,它们是不同的野兽,这就是你收到错误的原因。如您所见,模板参数列表是不同的。这不是具有分离定义的函数的声明。它们是两个不同的函数模板,一个声明,另一个声明和定义
换句话说,在您的代码中,您声明了一个友元函数,但您从未定义它。另一方面,您引入了一个免费的函数模板,该模板无法读取data
成员的私有,并且该函数不是A<Derived>
的朋友。
在wandbox上看到它正在运行。