我正在用C设计一个PEG解析器,该解析器应该同时支持std::string_view
和std::span<Token>
作为令牌流输入。
在代码中,我看到一个模板类只能由一些代码片段(如auto p2 = lit_(std::string_view("world"));
)示例化,而不能由代码auto p1 = lit_("world");
示例化。我的意思是模板推导不允许从C字符串常量转换为std::string_view
。这里是一个简化的代码来演示这个问题,它应该由C20构建。
#include <span>
#include <string_view>
#include <vector>
struct Token
{
};
template <typename T>
struct Viewer;
// explicit specialization for T = Token
template <>
struct Viewer<Token>
{
using type = std::span<Token>; // std::span or derived class
};
// explicit specialization for T = char
template <>
struct Viewer<char>
{
using type = std::string_view;
};
// alias template
template <typename T> using ViewerT = typename Viewer<T>::type;
template <typename Base, typename T>
struct parser_base {
using v = ViewerT<T>;
using charType = T;
};
// literal string match, for std::string_view, it could match a string
// for std::span<Token>, it will match a stream of Tokens defined by the span<Token>
template<typename V>
struct lit_ final : public parser_base<lit_<V>, typename V::value_type> {
/// @brief Construct a lit_ parser.
/// @param[in] str The string literal to parse.
//template<typename V>
constexpr lit_(V str) noexcept
: str(str)
{}
private:
V str;
};
int main()
{
//auto p1 = lit_("world"); // build error if uncommented
auto p2 = lit_(std::string_view("world"));
Token a;
std::vector<Token> tokens;
tokens.push_back(a);
tokens.push_back(a);
tokens.push_back(a);
std::span<Token> match(tokens.begin(), tokens.size());
auto p3 = lit_(match); //
return 0;
}
它演示了char
(std::string_view
)的流或Token
(std::span<Token>
)的流都可以构造为lit_
(字面量)。
有没有解决这个问题的办法?
谢谢。
2条答案
按热度按时间wfauudbj1#
模板参数推导不考虑隐式转换,这是正确的。
但是,您可以使用C++17 class template argument deduction。
Now your commented line compiles .
cgvd09ve2#
您可以使构造函数模板接受各种类型,这些类型可以转换为
std::string_view
或std::span<Token>
,并为构造函数提供一个 constrained 演绎指南这使得
lit_
接受任何可以转换为std::string_view
和std::span<Token>
的参数: