C++中的特定模板友谊

Specific Template Friendship in C++

本文关键字:友谊 C++      更新时间:2023-10-16

我有一个关于C++中特定模板友谊的问题。在《C++入门》一书中,具体的模板友谊是这样写的:

template <class T> class Foo3;
template <class T> void templ_fcn3(const T&);
template <class Type> class Bar {
// each instantiation of Bar grants access to the
// version of Foo3 or templ_fcn3 instantiated with the same type
friend class Foo3<Type>;
friend void templ_fcn3<Type>(const Type&);
// ...
};

特别的一点是有

<Type>

friend语句中的类名或函数名之后。

然而,在实践中,如果我这样写:

template <class Type> class T_CheckPointer;
template <class T> T_CheckPointer<T> operator+(const T_CheckPointer<T> &, const size_t n);
template <typename Type>
class T_CheckPointer {
// Specific Template Friendship
friend T_CheckPointer<Type>
operator+ <Type> (const T_CheckPointer<Type> &, const size_t n);
// other code...
}

在模板函数的实例化过程中会出现错误。

如果我更改

// Specific Template Friendship
friend T_CheckPointer<Type>
operator+ <Type> (const T_CheckPointer<Type> &, const size_t n);

// Specific Template Friendship
friend T_CheckPointer<Type>
operator+ <> (const T_CheckPointer<Type> &, const size_t n);

通过删除函数名称后面的单词type,一切都会好起来。

有人能告诉我原因吗?


有关信息,当我调用时,会出现错误消息

int iarr[] = {1, 2, 3, 4};
T_CheckPointer<int> itcp(iarr, iarr+4);

错误消息:

/usr/include/c++/4.4/bits/stl_iterator_base_types.h: In instantiation of ‘std::iterator_traits<int>’:
/usr/include/c++/4.4/bits/stl_iterator.h:96:   instantiated from ‘std::reverse_iterator<int>’
../Classes/T_CheckPointer.hpp:31:   instantiated from ‘T_CheckPointer<int>’
../PE16.cpp:520:   instantiated from here
/usr/include/c++/4.4/bits/stl_iterator_base_types.h:127: error: ‘int’ is not a class, struct, or union type
/usr/include/c++/4.4/bits/stl_iterator_base_types.h:128: error: ‘int’ is not a class, struct, or union type
/usr/include/c++/4.4/bits/stl_iterator_base_types.h:129: error: ‘int’ is not a class, struct, or union type
/usr/include/c++/4.4/bits/stl_iterator_base_types.h:130: error: ‘int’ is not a class, struct, or union type
/usr/include/c++/4.4/bits/stl_iterator_base_types.h:131: error: ‘int’ is not a class, struct, or union type

这里有一个最小的例子:

template<typename T> struct U { typedef typename T::X X; };
template<typename T> void foo(typename U<T>::X);
template<typename T> struct S;
template<typename T> void foo(S<T>);
template<typename T> struct S { friend void foo<T>(S<T>); };
template struct S<int>;

friend声明失败的原因是,通过提供模板参数的完整列表,您请求编译器专门化所有可用的函数模板,并选择最匹配签名的模板。CCD_ 2的第一个定义的专门化导致CCD_。

如果您省略了模板参数,它将从参数中推导出来。由于这样的模板参数推导是根据14.8.2[temp.dracte]执行的,特别是14.8.2p8适用,这意味着U专业化中的替换失败不是错误(SFINAE)。

这是一个很好的理由,可以省略任何可以从上下文推导出的模板参数(例如,这里的函数或运算符参数类型)。请注意,您仍然需要提供<>括号,以确保operator +被读取为模板id(14.5.4[temp.friend])。