C++17中noexcept引发Boost Spirit语义动作问题的原因解析——VS2019编译错误问询
noexcept cause a compilation error with Boost Spirit semantic actions in C++17? Let’s break down your problem clearly, since this ties into a critical C++17 change that reshapes how function types are handled.
First, to recap your scenario:
Your code compiles without issue in VS2019’s C14 mode, but fails when switching to C17 or C++20. The root cause is the
noexceptspecifier on theDuration::addHoursmethod.
1. Why does noexcept trigger the compilation error?
The core issue is a C++17 update to function type semantics:
- Before C++17,
noexceptwas just an attribute of a function—it didn’t change the function’s type signature. A member function likevoid (Duration::*)(uint64_t) noexceptcould be implicitly converted to its non-noexceptcounterpartvoid (Duration::*)(uint64_t)without any problems. - In C++17,
noexceptbecame a formal part of the function’s type. This means the two signatures above are now distinct, incompatible types—there’s no implicit conversion between them anymore.
Boost Phoenix’s bind mechanism (used in your semantic action phoenix::bind(&Duration::addHours, qi::_val, qi::_1)) wasn’t updated in older versions to account for this shift. It expects a member function pointer without the noexcept qualifier, and when presented with the qualified version, template type deduction fails outright.
2. Why does this become a problem specifically in C++17 for Boost Spirit?
Boost Spirit’s semantic actions depend heavily on Boost Phoenix to handle callable objects (like member function pointers) in rule definitions. Before C17, Phoenix could safely ignore noexcept because it didn’t affect type compatibility. But once C17 integrated noexcept into function types, older Phoenix implementations couldn’t resolve the type mismatch between the noexcept-qualified member function and the expected non-qualified type.
Put simply: older Boost versions weren’t designed to handle C++17’s new function type rules, so noexcept-qualified functions break Phoenix bind expressions used in Spirit semantic actions.
Possible Workarounds
- Remove the
noexceptspecifier: If your use case doesn’t strictly require it, this will immediately fix the compilation error by matching the function type Phoenix expects. - Upgrade your Boost library: Newer Boost versions (starting around 1.70+, depending on the component) have been updated to support C++17’s
noexceptfunction type changes. Upgrading may resolve the issue without modifying your code. - Wrap the member function: If you need to keep
noexcept, wrap the call in a lambda that hides the qualifier from Phoenix:auto addHoursWrapper = [](Duration& d, uint64_t val) { d.addHours(val); }; qi::rule<std::string::iterator, Duration()> durationRule = (int64_ >> "h")[phoenix::bind(addHoursWrapper, qi::_val, qi::_1)];
内容的提问来源于stack exchange,提问作者Steffen Roeber

