考虑以下代码:
template<typename T>
class Base
{
template<typename U>
friend void f(void *ptr) {
static_cast<Base<U>*>(ptr)->run();
}
protected:
virtual void run() = 0;
};
class A : public Base<A>
{
protected:
virtual void run() {}
};
/*
class B : public Base<B>
{
protected:
virtual void run() {}
};
*/
现在编译好(ideone)。但如果我取消注释B
的定义,则会出现以下错误(ideone):
prog.cpp: In instantiation of ‘Base<B>’:
prog.cpp:20: instantiated from here
prog.cpp:6: error: redefinition of ‘template<class U> void f(void*)’
prog.cpp:6: error: ‘template<class U> void f(void*)’ previously defined here
我知道(嗯,我想我知道)之所以会出现这个错误。
所以我的问题是:
如果在友元函数模板的类内定义的情况下如何避免重定义错误?
只要我在类中提供主模板(非专业化)的定义,我就会收到此错误。以这种方式定义主模板还有另一个问题:它使f
类模板的所有实例化的friend
函数模板Base
的所有实例化,我也想避免。如果f<T>
和Base<T>
不相同,我想让f<U>
成为Base<T>
的朋友,而不是U
T
的朋友。同时,我也想在课堂内提供定义。有可能吗?
答案 0 :(得分:4)
你真的需要在课堂上定义f
吗?如果您在外面定义它,您的问题就会消失,您也可以强制执行所需的一对一关系(即只有f<T>
是Base<T>
的朋友):
template <typename T> class Base;
template <typename U>
void f(void *ptr) {
static_cast<Base<U>*>(ptr)->run();
}
template<typename T>
class Base
{
friend void f<T>(void *ptr); //only one instanciation is a friend
protected:
virtual void run() = 0;
};
但请注意,只有f<T>
是Base<T>
的朋友的事实不会阻止以下代码编译:
B b;
f<A>(&b); // compiles, f<A> calls Base<A>::run, but the cast is wrong
答案 1 :(得分:1)
友元函数是一个全局函数,即使您将其实现放入任何类的主体中也是如此。问题是,当您实例化Base<T>
两次(在任何上下文中)时,您提供了两个f
的实现。请注意,f
不依赖于T
,并且无法使用T
;对于所有Base<T>
来说,它都是相同的功能。
一个简单的解决方案是只在类模板中提供f
的声明并在其外部实现:
template<typename T>
class Base
{
template<typename U>
friend void f(void *ptr);
protected:
virtual void run() = 0;
};
template<typename U>
void f(void *ptr) {
static_cast<Base<U>*>(ptr)->run();
}
class A : public Base<A>
{
protected:
virtual void run() {}
};
class B : public Base<B>
{
protected:
virtual void run() {}
};
int main() {
}
上面的代码用我的g ++编译