2011-05-25 105 views
3

我有一个sfinae类,它测试一个类是否是解析器规则(AX解析器生成器库)。 如果P满足解析器规则要求,axe::is_rule<P>::value应评估为true。解析器规则必须具有以下部件的功能之一,以一对迭代器和返回axe::result<Iterator>:如何编写SFINAE来测试解析器规则?

template<class Iterator> 
axe::result<Iterator> P::operator()(Iterator, Iterator); 

,或者它的专业化,或者非模板对于某些类型的图表

axe::result<CharT*> P::operator()(CharT*, CharT*); 

,或const以上版本。理论上,可以有一个以上的超载operator(),尽管实际上对于具有上述签名之一的单个operator()的测试就足够了。

不幸的是,is_rule目前的实施只处理一些情况,但不是全部情况。有一些不幸的类,该失败is_rule测试:

#define AXE_ASSERT_RULE(T)\ 
    static_assert(axe::is_rule<typename std::remove_reference<T>::type>::value, \ 
    "type '" #T "' is not a rule"); 

例如,以下不幸类型测试失败:

struct unfortunate 
{ 
    axe::result<const unsigned char*> 
    operator()(const unsigned char*, const unsigned char*); 
}; 

AXE_ASSERT_RULE(unfortunate); 

// or same using lambda 
auto unfortunate1 = [](const unsigned char*, const unsigned char*) 
->axe::result<const unsigned char*> {}; 
AXE_ASSERT_RULE(decltype(unfortunate1)); 


typedef std::vector<char>::iterator vc_it; 
struct unfortunate2 { axe::result<vc_it> operator()(vc_it, vc_it) const; }; 
AXE_ASSERT_RULE(unfortunate2); 

typedef axe::result<const char*> (unfortunate3)(const char*, const char*); 
AXE_ASSERT_RULE(unfortunate3); 

struct rule { template<class I> axe::result<I> operator()(I, I); }; 
class unfortunate4 : public rule {}; 
AXE_ASSERT_RULE(unfortunate4); 
在AX

当前的解决方案是包装那些在转发封套( class r_ref_t),当然这会产生句法瑕疵(毕竟,解析器生成器都是关于语法糖的)。

如何修改is_rule中的sfinae测试来涵盖上述不幸的情况?

回答

5

我认为is_rule的API是不够的。例如unfortunate只有在与const unsigned char*类型的迭代器一起使用时才是规则。如果您使用unfortunateconst char*,那么它不起作用,因此不是一个规则,对吧?

话虽这么说,如果你改变了API来:

template <class R, class It> struct is_rule; 

那么我认为这是C++ 11可行的。下面是一个原型:

#include <type_traits> 

namespace axe 
{ 

template <class It> 
struct result 
{ 
}; 

} 

namespace detail 
{ 

struct nat 
{ 
    nat() = delete; 
    nat(const nat&) = delete; 
    nat& operator=(const nat&) = delete; 
    ~nat() = delete; 
}; 

struct any 
{ 
    any(...); 

    nat operator()(any, any) const; 
}; 

template <class T> 
struct wrap 
    : public any, 
     public T 
{ 
}; 

template <bool, class R, class It> 
struct is_rule 
{ 
    typedef typename std::conditional<std::is_const<R>::value, 
             const wrap<R>, 
             wrap<R>>::type W; 

    typedef decltype(
       std::declval<W>()(std::declval<It>(), std::declval<It>()) 
        ) type; 

    static const bool value = std::is_convertible<type, axe::result<It>>::value; 
}; 

template <class R, class It> 
struct is_rule<false, R, It> 
{ 
    static const bool value = false; 
}; 

} // detail 

template <class R, class It> 
struct is_rule 
    : public std::integral_constant<bool, 
         detail::is_rule<std::is_class<R>::value, R, It>::value> 
{ 
}; 

struct unfortunate 
{ 
    axe::result<const unsigned char*> 
    operator()(const unsigned char*, const unsigned char*); 
}; 

#include <iostream> 

int main() 
{ 
    std::cout << is_rule<unfortunate, const unsigned char*>::value << '\n'; 
    std::cout << is_rule<unfortunate, const char*>::value << '\n'; 
} 

对于我这种打印出:

1 
0 

我所做的规则稍微更宽松的比你指定:返回类型仅须隐式转换为axe::result<It>。如果你真的想要它是完全axe::result<It>然后只是在std::is_same sub我std::is_convertible

我也制作is_rule派生自std::integral_constant。这对于标签调度可以非常方便。例如:

template <class T> 
void imp(T, std::false_type); 

template <class T> 
void imp(T, std::true_type); 

template <class T> 
void foo(T t) {imp(t, is_rule<T, const char*>());} 
+0

不幸的是,'is_rule'类不能采用迭代器类型,因为没有办法指定它。当创建规则表达式时,迭代器类型是未知的,不能被指定。例如,(运算符&see http://tinyurl.com/3kmmcmh)表达式'auto rule = A & B;'是迭代器不可知的,规则A和B可以采取各种迭代器形式或者是复合规则本身,但是我必须能够为任何兼容的迭代器调用'rule(i1,i2)'。只要所有规则都实现了模板化的'operator()',我很好,否则(重要的是lambda函数)''is_rule'测试不幸失败。 – 2011-05-25 22:20:59

+0

如果你想确定一个有限的迭代器集合,你可以修改上面的代码来检查任何有限的迭代器集合,如果规则适用于任何一组迭代器,则返回true。 – 2011-05-25 22:24:35

+0

我明白你的意思了。它会严重夸大代码,每个复合规则(并且有很多)必须为每个参数测试所有可能迭代器的所有可能组合。像这样:'template r_and_t < typename std :: enable_if :: type,It1> :: value | is_rule :: type,It2> :: value, R1> :: type, typename std :: enable_if :: type,It1> :: value | is_rule :: type,It2> :: value, R2> :: type > operator&(R1 && r1,R2 && r2);'... – 2011-05-25 22:54:27