На первый взгляд неоднозначные перегрузки функции шаблона

Первоначальная проблема, которую я пытался решить, когда наткнулся на это, заключалась в выборе 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_ifs должен оценить, чтобы истина (skipper_type явно не равно unused_type затем), и вызов должен быть неоднозначным. Где я ошибаюсь?

2

Решение

Проблема здесь заключается в том, как заключено в комментариях, что при использовании только U::skpэто может быть U выводится как ссылочный тип (т. е. при передаче синтаксического анализатора lvalue). Когда это происходит, вы получаете SFINAE, поскольку ссылочный тип, очевидно, не имеет вложенного что-нибудь.

Исправление — удалить ссылку из U с std::remove_reference так что у вас есть (sizeof(std::remove_reference<T>::type::skp) != 0), Обратите внимание, что typename здесь не нужен, т.к. ::skp указывает на то, что type должно быть типовое имя.

1

Другие решения

Других решений пока нет …

По вопросам рекламы [email protected]