微信公众号搜"智元新知"关注
微信扫一扫可直接关注哦!

如何编写SFINAE来测试解析器规则?

如何解决如何编写SFINAE来测试解析器规则?

| 我有一个sfinae类,用于测试某个类是否为解析器规则(AXE解析器生成器库)。 如果满足解析器规则要求,则“ 0”应评估为真。解析器规则必须具有以下成员函数之一,并带有一对迭代器并返回
axe::result<Iterator>
template<class Iterator>
axe::result<Iterator> P::operator()(Iterator,Iterator);
,或其专长,或某些CharT类型的非模板
axe::result<CharT*> P::operator()(CharT*,CharT*);
,或上述的const版本。从理论上讲,可以有一个以上的重载ѭ4though,尽管在实践中,对单个带有上述签名之一的
operator()
进行测试就足够了。 不幸的是,当前对“ 6”的实现只处理部分情况,而不是全部情况。有一些不幸的课程未能通过“ 6”测试:
#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
),这当然会创建语法疣(毕竟,解析器生成器全都与语法糖有关)。 您将如何修改ѭ6中的sfinae测试以覆盖上述不幸的情况?     

解决方法

我认为
is_rule
的API不够。例如,仅当与类型为“ 14”的迭代器一起使用时,“ 13”才是规则。如果您将
unfortunate
const 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,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>
,则只需将used22ѭ细分为我使用的
std::is_convertible
。 我还使ѭ6从from25衍生而来。这对于标记分派可能非常方便。例如。:
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*>());}
    

版权声明:本文内容由互联网用户自发贡献,该文观点与技术仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请发送邮件至 dio@foxmail.com 举报,一经查实,本站将立刻删除。