结构体重载operator>>编译失败:readAndCast未识别问题求助
readAndCast模板函数 我定义了如下结构体,并为其实现了CArchive的序列化运算符重载:
struct S_SPECIAL_EVENT { BOOL bEventAllDay{}; friend CArchive& operator<<(CArchive& rArchive, S_SPECIAL_EVENT const& rsSE) { const WORD wVersion = 1; return rArchive << wVersion << gsl::narrow<bool>(rsSE.bEventAllDay); } friend CArchive& operator>>(CArchive& rArchive, S_SPECIAL_EVENT &rsSE) { WORD wVersion{}; rArchive >> wVersion; rsSE.bEventAllDay = readAndCast<BOOL, bool>(rArchive); return rArchive; } };
编译时出现错误:
error C3861: 'readAndCast': identifier not found
该readAndCast模板函数已在应用程序头文件中定义:
template <typename T, typename U> T readAndCast(CArchive& ar) { U x; ar >> x; return static_cast<T> (x); }
我已经在当前文件中包含了该头文件,但编译仍然失败。后来我改成手动实现的方式解决了问题:
friend CArchive& operator>>(CArchive& rArchive, S_SPECIAL_EVENT &rsSE) { WORD wVersion{}; bool bData{}; rArchive >> wVersion; rArchive >> bData; rsSE.bEventAllDay = gsl::narrow<BOOL>(bData); return rArchive; }
但仍想了解原问题的原因。
原因分析
1. 模板名称查找规则触发的问题
你在友元operator>>中以显式指定模板参数的方式调用readAndCast:readAndCast<BOOL, bool>(rArchive)。这种情况下,readAndCast属于非依赖名称——编译器在解析operator>>的定义时,会立刻尝试查找这个名称,而非等到该运算符被实例化的阶段。
如果此时编译器还未读取到readAndCast的声明(比如头文件包含顺序错误:先包含结构体所在头文件,再包含定义readAndCast的头文件),就会报“标识符未找到”的错误。
2. 友元函数的作用域限制
在结构体内部定义的友元函数,其作用域是隐藏的——不会自动加入到结构体所在命名空间的全局作用域中,除非你在外部提前声明这个友元函数。如果readAndCast位于某个命名空间下,而友元operator>>内部既没有用命名空间限定(如ns::readAndCast),也没有通过using namespace ns;引入该命名空间,编译器同样无法找到它。
手动实现为何能解决?
手动实现的代码没有依赖外部的readAndCast模板,所有变量和调用的gsl::narrow都是编译器已能识别的名称,因此不会触发名称查找失败的问题。
内容的提问来源于stack exchange,提问作者Andrew Truckle

