如果我在模板类声明中定义了friend模板函数,如下所示,它可以编译。
#include <iostream>
template <typename T>
class X {
public:
X(int i) : n(i) {}
private:
T n;
template <typename U>
friend void doStuff(const X<T>& x, const U& u)
{
std::cout << (x.n + u) << std::endl;
}
};
int main()
{
X<int> x(1);
doStuff(x, 3);
return 0;
}
但是,如果我将doStuff()
的定义移出类decalaration,就在声明类X<>
之后,如下所示,它就无法编译。
template <typename U>
template <typename T>
void doStuff(const X<T>& x, const U& u)
{
std::cout << (x.n + u) << std::endl;
}
以下代码也没有。
template <typename U, typename T>
void doStuff(const X<T>& x, const U& u)
{
std::cout << (x.n + u) << std::endl;
}
那么我应该如何在类声明之外定义模板函数doStuff()
?
提前致谢。
答案 0 :(得分:5)
也许是这样:
template <typename T>
class X {
public:
X(int i) : n(i) {}
private:
T n;
template <typename U, typename V>
friend void doStuff(const X<U>& x, const V& u);
};
template <typename U, typename V>
void doStuff(const X<U>& x, const V& u)
{
std::cout << (x.n + u) << std::endl;
}
int main()
{
X<int> x(1);
doStuff(x, 3);
X<double> y(1.0);
doStuff(y, 3.5);
}
答案 1 :(得分:3)
@jrok提供了一个很好的解决方案。
将该函数声明为
template <typename U, typename V>
friend void doStuff(const X<U>& x, const V& u);
你说每个X和V都有一个函数doStuff。但是你问,如果U不是T怎么办?好吧,当你使用类型为X,int的参数调用doStuff时,模板参数推导的唯一可接受的结果是将类定义的类型T设置为int。
template <typename V>
friend void doStuff(const X<T>& x, const V& u);
实际上,它确实如此。但这意味着对于任何类型T
,您告诉编译器您将定义一个带X<T>
的函数,任何必需的T
,以及第二个参数是模板参数的位置。 请注意,第一个参数不是模板函数参数。
当用户使用类型为X<T>
的类时,无法通常说',使用此特定模式来了解如何定义< / em>一个函数doStuff,其中X<T>
是第一个参数。
所以,在课堂上你承诺它会存在,但是没有办法以模板的方式写出这个定义。它必须是
之类的东西template <typename T,typename U>
for_any_seen_template_instance_anywhere_in_the_program_< X<T> >::
void doStuff(const X<U>& x, const V& u){
... code.
}
没有这样的事情。另一种思考方式:写作时
doStuff(a,b);
如果第一个参数不是函数模板参数,则不会自动生成与第一个参数相关的任何内容。类模板的模板参数类型不会像模板函数参数那样自动推导出来。
但是,您可以为任何所需的X<T>
定义T
(正如您在声明中所承诺的那样),但您必须自己为每个必需的类型执行此操作:
template<typename V>
void doStuff(const X<int>& x, const V& u){
std::cout << (x.n + u) << std::endl;
}
编辑,回答以下评论。
确实,所有doStuff(X<U>,int)
都是X<T>
的朋友,无论T
和U
是什么类型。这意味着在doStuff体内,您可以访问类型为X<Q>
的对象的私有。在这种情况下,您没有将任何此类对象传递到函数中,但您可以在其中创建X<std::string>
并使用它的私有。这是您为不使用最初的内联而支付的价格。