另一个命名空间中的模板友元函数和CRTP

时间:2017-03-15 20:28:50

标签: c++

这让我在过去几个小时里疯狂,我似乎无法解决这个问题。我已将问题提炼到这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::fn1::f的朋友。但是,GCC抱怨A<Derived>是私有且无法访问的see this snippet on Coliru

这种结构是否可行?如果是这样,我怎么能绕过编译器抱怨A<Derived>::data无法访问? (公开宣传不是一种选择)。

1 个答案:

答案 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上看到它正在运行。