Первоначальная проблема, которую я пытался решить, когда наткнулся на это, заключалась в выборе parse_impl
версия:
U
) предоставляет поле с именем "skp"
используйте это поле;Я придумал следующий код:
// This variant compiles for parsers requiring a skipper:
template <typename I, typename U, typename A,
typename = typename std::enable_if<
not std::is_same<
typename std::remove_reference<U>::type::skipper_type,
qi::unused_type
>::value
>::type,
typename = void > // avoid redefinition (1 more overload not shown)
bool parse_impl(I & start, I end, U && parser, A & attr)
{
// qi::space by default:
return qi::phrase_parse(start, end, parser, qi::space, attr);
}
// This variant compiles for parsers providing skipper via 'skp' member:
template <typename I, typename U, typename A,
typename = typename std::enable_if<
not std::is_same<
typename std::remove_reference<U>::type::skipper_type,
qi::unused_type
>::value
&& (sizeof(U::skp) != 0)
>::type,
typename = void, typename = void > // avoid redefinition
bool parse_impl(I & start, I end, U && parser, A & attr)
{
// parser.skp is available:
return qi::phrase_parse(start, end, parser, parser.skp, attr);
}
Сайт вызова выглядит так:
pr.is_ok = parse_impl(pr.position, input.cend(), parser, pr.attr);
и это называется как для типов, имеющих skp
и те, которые не имеют.
И это компилируется (на gcc4.7), но я не понимаю, почему: когда skp
присутствует, выражения в обоих enable_if
s должен оценить, чтобы истина (skipper_type
явно не равно unused_type
затем), и вызов должен быть неоднозначным. Где я ошибаюсь?
Проблема здесь заключается в том, как заключено в комментариях, что при использовании только U::skp
это может быть U
выводится как ссылочный тип (т. е. при передаче синтаксического анализатора lvalue). Когда это происходит, вы получаете SFINAE, поскольку ссылочный тип, очевидно, не имеет вложенного что-нибудь.
Исправление — удалить ссылку из U
с std::remove_reference
так что у вас есть (sizeof(std::remove_reference<T>::type::skp) != 0)
, Обратите внимание, что typename
здесь не нужен, т.к. ::skp
указывает на то, что type
должно быть типовое имя.
Других решений пока нет …