2012-10-16 31 views
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表示方法应该评估为真(skipper_type显然不等于unused_type的话),以及呼叫应该是含糊不清的。我错在哪里?

+0

[减少的测试用例](http://liveworkspace.org/code/5a6093ff1c940b48071231ec1d1d12bf)至少是不明确的,我看不出我在那里做了什么不同。我只能猜测你的第三个重载,即带有'skp'的重载,实际上从某种程度上来说并不会被调用,如果这确实为你编译的话。也许把一些测试打印语句放在里面?最后,我建议阅读[本博客文章](http://rmartinho.github.com/2012/06/01/almost-static-if.html)以及[this](http://stackoverflow.com/q/12654067/500104)问题和[this](http://stackoverflow.com/a/9154394/500104)的答案。 :) – Xeo

+0

@Xeo:我终于钉上了它。实际上有一个区别:'代码中的sizeof(NoRef :: skp)'和'(sizeof(U :: skp)!= 0)'在我的。 'NoRef'终于带来了歧义! *巨大*感谢您的帮助和链接! – vines

+0

啊,所以你的问题是,当你通过一个左值(并且“U”被推断为一个参考)时,你会得到你的SFINAE。 :)事实上,[这是问题](http://liveworkspace.org/code/f35132f82751e262fd6a64515e11bebd)。 – Xeo

回答

1

这里的问题在评论中得出结论,当仅使用U::skp时,可能推断U为引用类型(即,当传递左值解析器时)。当发生这种情况时,你会得到SFINAE,作为参考类型显然没有嵌套任何东西

修复方法是从U删除对std::remove_reference的引用,以便您拥有(sizeof(std::remove_reference<T>::type::skp) != 0)。请注意,此处不需要typename,因为::skp表示type必须是类型名称。