gpt4 book ai didi

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

转载 作者:太空狗 更新时间:2023-10-29 20:47:14 25 4
gpt4 key购买 nike

我有一个 sfinae 类,用于测试一个类是否是解析器规则(AXE 解析器生成器库)。axe::is_rule<P>::value应该评估为真当且仅当 P 满足解析器规则要求。解析器规则必须具有以下成员函数之一,采用一对迭代器并返回 axe::result<Iterator> :

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

,或其特化,或某些类型 CharT 的非模板

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 测试以弥补上述不幸的情况?

最佳答案

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

也就是说,如果您将 API 更改为:

template <class R, class It> struct is_rule;

然后我认为这在 C++11 中是可行的。下面是一个原型(prototype):

#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我在哪里使用 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*>());}

关于c++ - 如何编写 SFINAE 来测试解析器规则?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/6130924/

25 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com