函数返回模板实体的概念

时间:2020-05-29 21:30:54

标签: c++ c++20 c++-concepts

我一直在尝试向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>>;
};

2 个答案:

答案 0 :(得分:2)

当然可以。

定义类型特征以从T中抽出std::optional<std::pair<T, std::string_view>>

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;

定义一个周围的类型特征,以尝试在调用T时将其从F中拉出:

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>>);

答案 1 :(得分:2)

引入一个辅助特征,以验证给定类型是否为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))>;
};

DEMO


或者,在单独的概念定义中使用辅助特性,以避免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;
};

DEMO 2