类模板友元函数模板定义问题:私有成员访问报错
尝试为类模板test定义用于创建实例的友元函数模板时遇到以下问题:
- 第一段代码编译报错,提示无法访问私有成员
test::_value - 第二段仅含单个模板参数的代码可正常运行,但添加第二个模板参数后失效
第一段代码(编译报错)
template <typename T> class test { T _value;//[58] public: T value() const { return _value; } template <typename Q> friend test create_test(Q&& q); }; template <typename T, typename Q> test<T> create_test(Q&& q) { test<T> temp; temp._value = (T)q;//[70] return temp; } int main() { auto t = create_test<int>(7.5f);//[77] cout << t.value() << endl; return 0; }
编译错误信息
||=== Build: Debug in Test (compiler: GNU GCC MinGW64 UCRT) =| ||
In instantiation of 'test create_test(Q&&) [with T = int; Q = float]':| |77|required from here|
|70|error: 'int test::_value' is private within this context| |58|note: declared private here|
||= Build failed: 1 error(s), 2 warning(s) (0 minute(s), 1 second(s)) ===|
第二段代码(单参数正常运行)
template <typename T> class test { T _value; public: T value() const { return _value; } friend test create_test<>(T); }; template <typename T> test<T> create_test(T value) { test<T> temp; temp._value = value; return temp; } int main() { auto t = create_test(100); cout << t.value() << endl; return 0; }
问题原因
第一段代码中,类模板test<T>内声明的友元是单模板参数Q的函数模板create_test(Q&&),但实际定义的是双模板参数T、Q的create_test(Q&&),二者并非同一个函数模板,因此友元关系不成立,导致无法访问私有成员_value。
第二段单参数代码能运行,是因为友元声明friend test create_test<>(T);特指了create_test<T>这个实例,与后续定义的单参数函数模板实例完全匹配,友元关系生效。
解决方法
方法1:提前声明双参数函数模板,修正友元声明
先在类模板外部声明双参数的create_test函数模板,再在类内声明友元时明确匹配该双参数模板:
// 提前声明函数模板与类模板 template <typename T> class test; template <typename T, typename Q> test<T> create_test(Q&& q); template <typename T> class test { T _value; public: T value() const { return _value; } // 声明双参数函数模板为友元 template <typename U, typename Q> friend test<U> create_test(Q&& q); }; template <typename T, typename Q> test<T> create_test(Q&& q) { test<T> temp; temp._value = static_cast<T>(q); // 推荐用static_cast替代C风格强制转换 return temp; } int main() { auto t = create_test<int>(7.5f); cout << t.value() << endl; return 0; }
方法2:在类模板内部直接定义友元函数模板
将create_test的定义直接放在类模板内部,编译器会自动关联函数模板与类的友元关系:
#include <iostream> using namespace std; template <typename T> class test { T _value; public: T value() const { return _value; } // 直接在类内定义友元函数模板 template <typename Q> friend test<T> create_test(Q&& q) { test<T> temp; temp._value = static_cast<T>(q); return temp; } }; int main() { auto t = create_test<int>(7.5f); cout << t.value() << endl; return 0; }
内容的提问来源于stack exchange,提问作者alex_87_xela

