The Phoenix library predates noexcept.
Since c++17 The noexcept-specification is a part of the function type and may appear as part of any function declarator.
The implication is that you run into limitations of Phoenix when using the noexcept specifications in c++17 mode.
Specifically, the thing that appears to break is return type deduction: Functions differing only in their exception specification cannot be overloaded (just like the return type, exception specification is part of function type, but not part of the function signature) (since C++17).
Improvements
In your case, since you're using C++17, why not simplify the whole thing? Live On Coliru
qi::rule<std::string::const_iterator, Duration()> durationRule //
= qi::eps[_val = 0s] //
>> (qi::int_ >> "h")[_val += _1 * 1h];
The output
"2m" -> failed
"3h" -> 10800
"4s" -> failed
gives away my intent!
Bonus Extension 1: units
Using a simple table like
qi::symbols<char, Duration> unit_;
unit_.add
("ns", 1ns) ("nano", 1ns)
("us", 1us) ("μs", 1us) ("micro", 1us)
("ms", 1ms) ("milli", 1ms)
("s", 1s)
("m", 1min) ("min", 1min)
("h", 1h) ("hour", 1h)
("d", 24h) ("day", 24h)
;
Now with the trivial change of
>> +(qi::int_ >> unit_)[_val += _1 * _2];
It does evaluates a boatload of interesting sequences: Live On Coliru
#include <boost/spirit/include/phoenix.hpp>
#include <boost/spirit/include/qi.hpp>
#include <chrono>
#include <iomanip>
using namespace std::chrono_literals;
using Duration = std::chrono::duration<int64_t, std::nano>;
namespace qi = boost::spirit::qi;
int main()
{
using namespace qi::labels; // _val, _1 etc
qi::symbols<char, Duration> unit_;
unit_.add
("ns", 1ns) ("nano", 1ns)
("us", 1us) ("μs", 1us) ("micro", 1us)
("ms", 1ms) ("milli", 1ms)
("s", 1s)
("m", 1min) ("min", 1min)
("h", 1h) ("hour", 1h)
("d", 24h) ("day", 24h)
;
qi::int_parser<int64_t, 10> int64_;
qi::rule<std::string::const_iterator, Duration(), qi::blank_type>
durationRule //
= qi::eps[_val = 0s] //
>> +(int64_ >> unit_)[_val += _1 * _2];
for (std::string const s :
{
"2m",
"3h",
"4s",
"1ms -1ns",
"1 day -23h",
"3600000000ns",
"1 day -23h -50m +3600000000ns",
}) //
{
std::cout << std::quoted(s);
Duration d{};
if (phrase_parse( //
s.begin(), s.end(), //
durationRule >> qi::eoi, //
qi::blank, d))
std::cout << " -> " << d / 1.0s << "s\n";
else
std::cout << " -> failed\n";
}
}
Prints
"2m" -> 120s
"3h" -> 10800s
"4s" -> 4s
"1ms -1ns" -> 0.000999999s
"1 day -23h" -> 3600s
"3600000000ns" -> 3.6s
"1 day -23h -50m +3600000000ns" -> 603.6s
Note I've shifted some details around to make it work. Notably qi::eoi
to check the entire input is consumed, and declaring the skipper in the rule (blank
instead of space
to exclude newlines). Without that, the rule was implicitly lexeme anyways (Boost spirit skipper issues)