如何将requires子句和一个参数包相互关联的参数提取成一个概念?

How to extract requires clause with a parameter pack whose parameters are related to each other into a concept?

我有这么一套玩具功能:

template <typename... Args>
requires std::conjunction_v<std::is_convertible<Args, int>...>
void test(Args...) { std::cout << "int"; }

template <typename... Args>
requires std::conjunction_v<
    std::disjunction<std::is_convertible<Args, int>,
                     std::is_convertible<Args, std::string>>...> &&
    std::disjunction_v<std::is_convertible<Args, std::string>...>
void test(Args...) { std::cout << "istring"; }

当我使用所有可转换为 int 且不可转换为 std::string 的参数时,将调用第一个函数,例如:test(1, 2L, 3.0, 4UL).

如果至少有一个参数可以转换为 std::string,并且如果所有参数都可以转换为 int 或 std::string,则将调用第二个函数,例如 test(1, 2L, "Hello", 4UL)

和我预期的一样。

但是,当我将第二个函数编码为以下两种样式时,它不起作用。 arguments的概念一一检查,1, 2L, 4UL不是Istring.

template <typename... Args>
concept Istring = std::conjunction_v<
    std::disjunction<std::is_convertible<Args, int>,
                     std::is_convertible<Args, std::string>>...> &&
    std::disjunction_v<std::is_convertible<Args, std::string>...>;

void test(Istring auto...) { std::cout << "istring"; }
template <typename... Args>
concept Istring = std::conjunction_v<
    std::disjunction<std::is_convertible<Args, int>,
                     std::is_convertible<Args, std::string>>...> &&
    std::disjunction_v<std::is_convertible<Args, std::string>...>;

template <IString... Args>
void test(Args...) { std::cout << "istring"; }

我想知道是否有提取概念的方法。

在这种情况下不需要使用 std::conjunctionstd::disjunction,因为它会使代码冗长且难以阅读。使用倍表达式会更直观。

template <typename... Args>
  requires (std::is_convertible_v<Args, int> && ...)
void test(Args...) { std::cout << "int\n"; }

template <typename... Args>
concept Istring = 
  ((std::is_convertible_v<Args, int> || 
    std::is_convertible_v<Args, std::string>) && ...) && 
  (std::is_convertible_v<Args, std::string> || ... );

template <Istring... Args>
void test(Args...) { std::cout << "istring\n"; }

在上面的例子中,Istring只会约束一个单个参数,而不是参数包,即检查是否每个 参数满足以下退化约束:

template <typename T>
concept Istring = 
  (std::is_convertible_v<T, int> || std::is_convertible_v<T, std::string>) && 
  std::is_convertible_v<T, std::string>;

您应该使用 requires 子句来检查所有参数,例如:

template <typename... Args>
  requires Istring<Args...>
void test(Args...) { std::cout << "istring\n"; }

Demo.