模板 class 中友元声明的附加模板参数?
Additional template arguments for friend declaration in template class?
为了一些全局函数
template<typename T, int count>
void func (const Obj<T>& obj) {
for (int i = 0; i < count; i++)
std::cout << obj.value << std::endl;
}
能够访问某些模板 class
的私有字段 value
template<typename T>
class Obj {
public:
Obj (T value);
private:
T value;
};
template<typename T>
Obj<T>::Obj (T value) : value(value) {}
我们需要声明 func<T, count>
为 Obj<T>
的朋友。但是 func<T, count>
必须先声明才能使它成为 Obj<T>
的友元,为此我们需要前向声明 Obj<T>
。生成的代码如下所示
// Forward declarations
template<typename T>
class Obj;
template<typename T, int count>
void func (const Obj<T>& obj);
// Obj<T>
template<typename T>
class Obj {
public:
Obj (T value);
template<int count>
friend void func<T, count> (const Obj<T>& obj);
private:
T value;
};
template<typename T>
Obj<T>::Obj (T value) : value(value) {} // <-- ERROR
// func<T>
template<typename T, int count>
void func (const Obj<T>& obj) {
for (int i = 0; i < count; i++)
std::cout << obj.value << std::endl;
}
但这让 gcc 抱怨 "invalid use of template-id 'func' in declaration of primary template",那么我如何为每个 count
实际声明 func<T, count>
Obj<T>
的朋友?根据 this answer 我只需要用这个
替换朋友声明
template<typename T1, int count>
friend void func (const Obj<T1>& obj);
据我所知,这会使 func<T1, count>
成为 Obj<T>
的朋友,而不管 T1
和 T
是否匹配,这是荒谬的。是否可以声明 func<T, count>
是 Obj<T>
的朋友而不是其他 Obj<T1>
的朋友? (最好是将 func<T, count>
的定义保持在 Obj<T>
的定义之外)
(我知道我可以让 count
成为一个真实的参数,但上面的例子只是我真实代码的简化。实际上我试图为一些 std::basic_ostream<CharT, Traits>& operator<< (std::basic_ostream<CharT, Traits>& stream, const Obj<T>& obj)
重载 class Obj<T>
允许 operator<<
访问 Obj<T>
的私有字段。)
friend
声明必须匹配任何可能的前向声明,当然还有定义,包括模板参数。
这意味着您需要例如
template<typename U, int count>
friend void func(const Obj<U>& obj);
class 模板参数 T
和函数模板参数 U
是否不同并不重要,因为无论如何都会对正确的函数进行调用。
示例:
Obj<int> int_obj;
Obj<float> float_obj;
func<X>(int_obj); // Will call void func<int, X>(int_obj)
func<X>(float_obj); // Will call void func<float, X>(float_obj)
作为替代方案,您可以在 class 定义中 define 内联函数,然后您不需要提供 T
或U
模板参数:
template<int count>
friend void func(const Obj<T>& obj)
{
// Implementation...
}
而且在这两种情况下你都应该有一个 func
的前向声明(正如我的评论中提到的)。
为了一些全局函数
template<typename T, int count>
void func (const Obj<T>& obj) {
for (int i = 0; i < count; i++)
std::cout << obj.value << std::endl;
}
能够访问某些模板 class
的私有字段value
template<typename T>
class Obj {
public:
Obj (T value);
private:
T value;
};
template<typename T>
Obj<T>::Obj (T value) : value(value) {}
我们需要声明 func<T, count>
为 Obj<T>
的朋友。但是 func<T, count>
必须先声明才能使它成为 Obj<T>
的友元,为此我们需要前向声明 Obj<T>
。生成的代码如下所示
// Forward declarations
template<typename T>
class Obj;
template<typename T, int count>
void func (const Obj<T>& obj);
// Obj<T>
template<typename T>
class Obj {
public:
Obj (T value);
template<int count>
friend void func<T, count> (const Obj<T>& obj);
private:
T value;
};
template<typename T>
Obj<T>::Obj (T value) : value(value) {} // <-- ERROR
// func<T>
template<typename T, int count>
void func (const Obj<T>& obj) {
for (int i = 0; i < count; i++)
std::cout << obj.value << std::endl;
}
但这让 gcc 抱怨 "invalid use of template-id 'func' in declaration of primary template",那么我如何为每个 count
实际声明 func<T, count>
Obj<T>
的朋友?根据 this answer 我只需要用这个
template<typename T1, int count>
friend void func (const Obj<T1>& obj);
据我所知,这会使 func<T1, count>
成为 Obj<T>
的朋友,而不管 T1
和 T
是否匹配,这是荒谬的。是否可以声明 func<T, count>
是 Obj<T>
的朋友而不是其他 Obj<T1>
的朋友? (最好是将 func<T, count>
的定义保持在 Obj<T>
的定义之外)
(我知道我可以让 count
成为一个真实的参数,但上面的例子只是我真实代码的简化。实际上我试图为一些 std::basic_ostream<CharT, Traits>& operator<< (std::basic_ostream<CharT, Traits>& stream, const Obj<T>& obj)
重载 class Obj<T>
允许 operator<<
访问 Obj<T>
的私有字段。)
friend
声明必须匹配任何可能的前向声明,当然还有定义,包括模板参数。
这意味着您需要例如
template<typename U, int count>
friend void func(const Obj<U>& obj);
class 模板参数 T
和函数模板参数 U
是否不同并不重要,因为无论如何都会对正确的函数进行调用。
示例:
Obj<int> int_obj;
Obj<float> float_obj;
func<X>(int_obj); // Will call void func<int, X>(int_obj)
func<X>(float_obj); // Will call void func<float, X>(float_obj)
作为替代方案,您可以在 class 定义中 define 内联函数,然后您不需要提供 T
或U
模板参数:
template<int count>
friend void func(const Obj<T>& obj)
{
// Implementation...
}
而且在这两种情况下你都应该有一个 func
的前向声明(正如我的评论中提到的)。