如何编写SFINAE来测试语法分析器规则
How to write SFINAE to test for parser rule?
我有一个sfinae类,它测试一个类是否是解析器规则(AXE解析器生成器库)。如果P满足解析器规则要求,则axe::is_rule<P>::value
应评估为真。解析器规则必须具有以下成员函数之一,采用一对迭代器并返回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);
AXE中当前的解决方案是将它们封装在转发包装器(class r_ref_t
)中,这当然会产生语法缺陷(毕竟,解析器生成器完全是关于语法糖的)。
您将如何修改is_rule
中的sfinae测试以涵盖上述不幸情况?
我认为is_rule
的API是不够的。例如,仅当与类型为const unsigned char*
的迭代器一起使用时,unfortunate
才是规则。如果您将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, 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
。
我还使CCD_ 18衍生自CCD_ 19。这对于标签调度来说非常方便。例如:
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*>());}
- 1d 智能指针不适用于语法 (*)++
- 使用 gperftools 的堆分析器来分析 libc malloc
- 在手写语法分析器中翻译语法文件
- 我们是否可以使用 g++ 编译代码通过 Solaris Studio 的性能分析器进行性能分析?
- 手工编写的递归上升语法分析器中的递归左递归
- GLSL 语法错误:"in"分析错误
- C++.obj语法分析器面
- 无序时分析逗号分隔的语法
- 递归下降分析和语法树
- 将qi::十六进制语法分析器限制为2个字符
- 编译错误,带有boost::spirit语法分析器
- Sequential Or语法分析器a||b
- 用于从文件填充类的词法分析器/解析器的语法规则
- 词汇和语法分析器软件
- 在气的精神中回滚替代语法分析器的变化
- 在递归下降语法分析器中避免了递归算法中的stackoverflow
- 使用Alternative语法分析器提高spirit较差的性能
- Lexer和来自EBNF的C++语法分析器
- 助推::精神::气.如何将内联语法分析器表达式转换为独立语法,以及如何解压缩它们生成的元组
- 如何编写SFINAE来测试语法分析器规则