当我偶然发现这个问题时,我试图解决的原始问题是选择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);
    }
    

    call 站点如下所示:
    pr.is_ok = parse_impl(pr.position, input.cend(), parser, pr.attr);
    

    对于有skp的类型和没有skp的类型,都将调用它。

    它可以编译(在gcc4.7上),但是我不明白为什么:当存在enable_if时,两个skipper_type中的表达式都应评估为true(然后unused_type显然不等于ojit_code),并且该调用应是模棱两可的。我在哪里弄错了?

    最佳答案

    正如评论中所总结的那样,这里的问题是,仅使用U::skp时,可能是U被推导为引用类型(即,传递左值解析器时)。发生这种情况时,您可以使用SFINAE,因为引用类型显然没有嵌套任何内容。

    解决方法是使用Ustd::remove_reference中删除引用,以便您拥有(sizeof(std::remove_reference<T>::type::skp) != 0)。请注意,此处不需要typename,因为::skp表示type必须为类型名。

    10-08 11:56