MSVC编译含offsetof的参数包模板函数报C1903错误咨询
MSVC 2017中模板参数包函数内使用offsetof报错:这是编译器Bug
首先可以明确地说:这绝对是Microsoft Visual Studio 2017(MSVC 15.6.85.37198)的编译器Bug,你的代码完全符合C++17标准,没有违反规范或触发未定义行为。
为什么代码是合法的?
根据C++17标准的规定,offsetof宏的使用满足两个核心条件即可:
- 第一个参数是标准布局类型(standard-layout type);
- 第二个参数是该类型的非静态数据成员。
你的Point结构体所有成员都是公共访问权限,没有虚函数、复杂基类等破坏标准布局的元素,属于标准布局类型;x是它的非静态数据成员,所以offsetof(Point, x)的调用本身完全合法。
另外,模板函数doSomething虽然带有参数包Ps...,但你调用的是doSomething()(空参数包实例化),此时offsetof的调用完全不依赖模板参数,是一个独立的常量表达式。Clang和G++都能正常编译这段代码,也从侧面证明了代码的合规性。
MSVC的问题根源
MSVC 2017的这个版本在处理带有参数包的模板函数时,对offsetof宏的解析存在逻辑错误——它错误地将offsetof的解析流程和模板参数包的处理绑定在一起,导致无法正确识别合法的offsetof调用,最终抛出无法恢复的编译错误。
临时解决方案
如果需要在这个MSVC版本下编译代码,可以尝试以下两种绕过方法:
- 提前预计算
offsetof结果为常量,在模板函数内直接使用:#include <cstddef> struct Point { double x; double y; double z; }; constexpr size_t PointXOffset = offsetof(Point, x); template<class... Ps> void doSomething() { (void)PointXOffset; // 直接使用预计算的常量 } int main() { doSomething(); } - 将
offsetof调用封装到非模板函数中,在模板函数内调用这个封装函数:#include <cstddef> struct Point { double x; double y; double z; }; size_t getPointXOffset() { return offsetof(Point, x); } template<class... Ps> void doSomething() { (void)getPointXOffset(); } int main() { doSomething(); }
这两种方法都能避开MSVC的解析bug,让代码正常编译。
内容的提问来源于stack exchange,提问作者Ebatsin
相关产品推荐
相关产品推荐

