将参数包约束为类字符串类型或可转换为字符串的类型的概念



我正在拼凑一个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点的有用信息。然而,对于第1)和第3)点,我却毫无头绪(我也是概念新手)。如何约束整个参数包(这里的语法是什么?)以及如何确保每个参数都可以构造一个std::string对象?

而且,我必须在编译时知道我是想使用std::strings构造函数还是std::to_string来处理这种情况。

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

你想要的是这样的:

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_string是可的。

无论如何,要允许to_string工作,我们需要更改代码以连接此表达式:std::to_string(std::forward<Ts>(args))。但是那将只接受to_string工作的类型,而不是可转换为string的类型。

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

所以我们有两种类型:一种是固有的字符串可连接的,另一种是to_string可连接的:

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

相关内容

  • 没有找到相关文章

最新更新