【问题标题】:Concept for constraining parameter pack to string-like types or types convertible to string将参数包限制为类字符串类型或可转换为字符串的类型的概念
【发布时间】:2022-11-24 00:48:54
【问题描述】:

我正在拼凑一个 C++20 难题。这是我想要做的:函数append_params 将 url 与其他查询参数连接在一起。为了以动态和可扩展的方式进行设计,我想写一个这样的概念

  1. 它允许可以从中构造 std::string 的类型

  2. 它允许使用 std::to_string() 将类型转换为字符串

     template<typename... Ts> requires requires(T a) { std::to_string(a); }
     auto append_params(std::pmr::string url, Ts... args) {
    
     }
    
  3. 它适用于一组参数

    我在第 2 点找到了有用的信息)here。但是,对于第 1) 点和第 3) 点,我相当无能为力(我也是概念新手)。我如何约束整个参数包(这里的语法是什么?)以及如何确保我可以从每个参数构造一个 std::string 对象?

    另外,如果我想使用 std::strings 构造函数或 std::to_string 来处理这种情况,我必须在编译时知道。

【问题讨论】:

  • 它适用于一组参数" 为什么有必要?如果一个概念处理 1 和 2,那么你可以只说 template&lt;concept_name ...Pack&gt;。这个概念本身不需要能够得到一个包。
  • @NicolBolas 对!没想到谢谢!
  • 此外,您使用的示例代码使用pmr::stringto_string 不使用 pmr::string;它只返回std::string。使用pmr::string 的主要原因是因为您想在堆外进行所有必要的内存分配。 to_string 做不到。那么,您确定要在这里使用to_string吗?
  • @NicolBolas 对,没有std::to_pmr_string()...你是对的,我的选择有点有限。
  • “旧的”“转发到实施”方式:template &lt;typename... Ts&gt; auto append_params(Url url, Ts... args) -&gt; decltype(((url += to_string(args)), ...)) { return ((url += to_string(args)), ...); }

标签: c++ c++20 stdstring c++-concepts parameter-pack


【解决方案1】:

在开发一个概念时,总是从要约束的模板代码开始。您可能会在某个时候调整该代码,但您总是希望从该代码开始(不受约束)。

所以你想要的是这样的:

 template<typename... Ts>
 auto append_params(std::string &url, Ts... &&args)
 {
    return (url + ... + std::forward<Ts>(args) );
 }

如果 args 中的任何类型不是 std::strings 或可以与 std::string 连接的类型,这将不起作用。但是你想要更多。您想要采用 std::to_string 可以使用的类型。

请注意,这是一个非常糟糕的接口,因为std::to_string 不能被用户扩展。它们可以使它们的类型可转换为 std::string 或其他一些可连接的字符串类型,如 string_view。但是用户无法向std 库内容添加重载,因此他们无法创建to_stringable 类型。

无论如何,要允许to_string 工作,我们需要更改代码以与此表达式连接:std::to_string(std::forward&lt;Ts&gt;(args))。但那样会只要采用 to_string 可以使用的类型,而不是可转换为 string 的类型。

所以我们需要的是一个新函数,如果合适,它将使用to_string,或者如果可以直接连接,则只返回原始表达式。

所以我们有两种类型:那些本质上是可字符串连接的,以及那些是 to_string-able 的:

template<typename T>
concept is_direct_string_concatenatable = requires(std::string str, T t)
{
  {str + t} -> std::same_as<std::string>;
};

template<typename T>
concept is_to_stringable = requires(T t)
{
  {std::to_string(t)} -> std::same_as<std::string>;
};

//Combines the two concepts.
template<typename T>
concept is_string_concatenable =
  is_direct_string_concatenatable<T> ||
  is_to_stringable <T>;

template<is_string_concatenable T>
decltype(auto) make_concatenable(T &&t)
{
  //To_string gets priority.
  if constexpr(is_to_stringable<T>)
    return std::to_string(std::forward<T>(t));
  else
    return std::forward<T>(t);
}

所以现在你的模板函数需要使用 make_concatenable 和概念:

template<is_string_concatenable ...Ts>
auto append_params(std::string url, Ts&& ...args)
{
   return (url + ... + make_concatenable(std::forward<Ts>(args)));
}

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2017-12-30
    • 1970-01-01
    • 1970-01-01
    • 2019-10-09
    • 2020-11-22
    • 2018-08-16
    • 2021-03-30
    相关资源
    最近更新 更多