2

これに遭遇したときに私が解決しようとした元の問題は、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の式がtrueと評価され(skipper_type明らかにunused_typethenと等しくない)、呼び出しがあいまいになるはずです。どこが間違っているの?

4

1 に答える 1

1

ここでの問題は、コメントで結論付けられているように、を使用する場合U::skp、それが参照型として推定される可能性があることUです(つまり、左辺値パーサーを渡す場合)。これが発生すると、参照型には明らかにネストされたものがないため、SFINAEが実行されます。

修正は、で参照を削除して、を取得するUことstd::remove_referenceです(sizeof(std::remove_reference<T>::type::skp) != 0)。はタイプ名である必要があることを示しているtypenameため、ここでは必要ないことに注意してください。::skptype

于 2012-10-25T00:42:09.003 に答える