返回模板化实体的函数的概念
Concept for a function returning a templated entity
我一直在尝试将概念添加到 constexpr json parser 中,并且正在努力定义正确的 Parser
概念。我的第一次尝试:
using parse_input_t = std::string_view;
template <typename T>
using parse_result_t = std::optional<std::pair<T, std::string_view>>;
// A parser for type `T` is a function: parse_input_t -> parse_result_t<T>
template <typename F, typename T>
concept Parser = std::is_invocable_r_v<parse_result_t<T>, F, parse_input_t>;
这个问题是我想用签名编写函数:
template <Parser P>
auto func(P p);
也就是我不想在界面中T
我可以用丑陋的东西来完成我想要的:
template <typename F>
concept Parser = requires(F f, parse_input_t i)
{
requires requires(typename decltype(f(i))::value_type result)
{
{ f(i) } -> std::same_as<parse_result_t<decltype(result.first)>>;
};
};
有没有更简洁的方法来做到这一点?我希望是这样的:
template <typename F>
concept Parser = requires(F f, parse_input_t i)
{
{ f(i) } -> std::same_as<parse_result_t<auto>>;
};
当然可以。
定义一个类型特征以从 std::optional<std::pair<T, std::string_view>>
:
中提取 T
template <typename T>
struct parser_type;
template <typename T>
struct parser_type<std::optional<std::pair<T, std::string_view>>> {
using type = T;
};
template <typename T>
using parser_type_t = typename parser_type<T>::type;
围绕它定义一个类型特征,当您调用 F
:
时,它会尝试拉出 T
template <typename F>
using parser_result = parser_type_t<std::invoke_result_t<F, std::string_view>>;
并围绕它建立一个概念:
template <typename F>
concept Parser = requires {
typename parser_result<F>;
};
然后您可以使用 parser_result<F>
作为解析器的 关联类型 。例如:
struct Ints {
auto operator()(std::string_view) -> std::optional<std::pair<int, std::string_view>>;
};
static_assert(Parser<Ints>);
static_assert(std::same_as<int, parser_result<Ints>>);
引入一个辅助特征来验证给定类型是否为 parse_result_t
,然后在 decltype(f(i))
:
的概念中使用它
template <typename T>
constexpr bool is_parse_result_v = false;
template <typename T>
constexpr bool is_parse_result_v<parse_result_t<T>> = true;
template <typename F>
concept Parser = requires(F f, parse_input_t i)
{
f(i);
requires is_parse_result_v<decltype(f(i))>;
};
或者,在单独的概念定义中使用 helper trait,以避免 decltype
:
template <typename T>
concept is_parse_result = is_parse_result_v<T>;
template <typename F>
concept Parser = requires(F f, parse_input_t i)
{
{ f(i) } -> is_parse_result;
};
我一直在尝试将概念添加到 constexpr json parser 中,并且正在努力定义正确的 Parser
概念。我的第一次尝试:
using parse_input_t = std::string_view;
template <typename T>
using parse_result_t = std::optional<std::pair<T, std::string_view>>;
// A parser for type `T` is a function: parse_input_t -> parse_result_t<T>
template <typename F, typename T>
concept Parser = std::is_invocable_r_v<parse_result_t<T>, F, parse_input_t>;
这个问题是我想用签名编写函数:
template <Parser P>
auto func(P p);
也就是我不想在界面中T
我可以用丑陋的东西来完成我想要的:
template <typename F>
concept Parser = requires(F f, parse_input_t i)
{
requires requires(typename decltype(f(i))::value_type result)
{
{ f(i) } -> std::same_as<parse_result_t<decltype(result.first)>>;
};
};
有没有更简洁的方法来做到这一点?我希望是这样的:
template <typename F>
concept Parser = requires(F f, parse_input_t i)
{
{ f(i) } -> std::same_as<parse_result_t<auto>>;
};
当然可以。
定义一个类型特征以从 std::optional<std::pair<T, std::string_view>>
:
T
template <typename T>
struct parser_type;
template <typename T>
struct parser_type<std::optional<std::pair<T, std::string_view>>> {
using type = T;
};
template <typename T>
using parser_type_t = typename parser_type<T>::type;
围绕它定义一个类型特征,当您调用 F
:
T
template <typename F>
using parser_result = parser_type_t<std::invoke_result_t<F, std::string_view>>;
并围绕它建立一个概念:
template <typename F>
concept Parser = requires {
typename parser_result<F>;
};
然后您可以使用 parser_result<F>
作为解析器的 关联类型 。例如:
struct Ints {
auto operator()(std::string_view) -> std::optional<std::pair<int, std::string_view>>;
};
static_assert(Parser<Ints>);
static_assert(std::same_as<int, parser_result<Ints>>);
引入一个辅助特征来验证给定类型是否为 parse_result_t
,然后在 decltype(f(i))
:
template <typename T>
constexpr bool is_parse_result_v = false;
template <typename T>
constexpr bool is_parse_result_v<parse_result_t<T>> = true;
template <typename F>
concept Parser = requires(F f, parse_input_t i)
{
f(i);
requires is_parse_result_v<decltype(f(i))>;
};
或者,在单独的概念定义中使用 helper trait,以避免 decltype
:
template <typename T>
concept is_parse_result = is_parse_result_v<T>;
template <typename F>
concept Parser = requires(F f, parse_input_t i)
{
{ f(i) } -> is_parse_result;
};