不受约束的 requires-expression 参数

Unconstrained requires-expression parameter

我可以在概念的 C++20 约束中使用约束泛型类型吗?举个例子,假设我想写一个要求,候选人 class T 有一个函数 func 可以接受满足 std::ranges::range 的任何类型的参数:

template<typename T>
concept Foo = requires (T t, std::ranges:range s) {
    { t.func(a); } -> std::convertible_to<double>;
}

但是 GCC 给我一条错误消息,指出在我放置 std::ranges::range.

的地方不能使用占位符类型

在我看来,您正在寻找一个具有(仅声明)operator T () 的结构,用于通用 T

struct generic_argument
 {
   template <typename T>
   operator T () const;
 };

因此您可以为每个预期参数和模板参数传递它(在 decltype() 内)。

所以你的概念(抱歉......我简化了它删除了范围参数)变成了(如果我明白你想要什么)

template<typename T>
concept Foo 
   = std::convertible_to<decltype(std::declval<T>().func(std::declval<generic_argument>())),
                         double>;

下面是一个完整的编译示例

#include <iostream>

struct A { double func (int a) { return a; } };
struct B { double not_func (long a) { return a; } };
struct C { std::string func (char) { return "abc"; } };
struct D { float func (auto) { return 1.0f; } };

struct E { double func (int a) { return a; }
           std::string func (char) { return "abc"; } };

struct generic_argument
 {
   template <typename T>
   operator T () const;
 };

template<typename T>
concept Foo 
   = std::convertible_to<decltype(std::declval<T>().func(std::declval<generic_argument>())),
                         double>;

template <Foo T>
void bar (T const &)
 { std::cout << "bar, Foo version\n"; }

template <typename T>
void bar (T const &)
 { std::cout << "bar, generic version\n"; }

int main()
 {
   bar(A{}); // print bar, Foo version
   bar(B{}); // print bar, generic version [no func() function]
   bar(C{}); // print bar, generic version [no convertible to double]
   bar(D{}); // print bar, Foo version
   bar(E{}); // print bar, generic version [two func() function]
 }

我对 E 情况有疑问:两种 func() 方法,只有一种 return 类型可转换为 double,来自 bar(E{})我们得到“酒吧,通用版本”。

我了解到,不,这是不可能的。 Arthur O'Dwyer 的以下文章解释说,一般来说,C++20 概念无法检查数学量词 (https://quuxplusone.github.io/blog/2020/08/10/concepts-cant-do-quantifiers/)

People frequently ask how to do things like this in C++20:

Make a concept Renderer that is satisfied if and only if t.render(u) is valid for all Printable types U. (From /r/cpp.)

Make a concept ValidSize that is satisfied if and only if t is convertible to some integral type U. (From the standard.)

上面的关键词是“全部”和“一些”。在数学中,这些被称为通用量词和存在量词:

渲染器⇔∀U∈可打印:t.render(u)格式正确

ValidSize ⇔ ∃U∈积分: U u = t;格式正确

C++20 概念不支持任何量词。

...

我问题中的示例与下面的 Renderer 示例相同,要求概念检查 T t 是否具有 func,其中 t.func(a) 的格式是否正确满足 std::ranges::range 的所有类型 A。这使用了 C++20 概念无法检查的通用量词。


至于 C++20 是否可能支持这样的事情,根据我从 等评论中收集到的信息,这甚至是不可能的,因为它减少到解决停机问题。在与文章作者 Arthur O'Dwyer 的直接对话中,他指出在某些时候约束必须归结为一个封闭的、完全指定的具体类型列表:

the only thing that'll help is to get rid of the quantifiers and deal with closed sets of types. For example, you can't do

template<typename T>
concept Foo = requires(T t) { t.func(a); };  // FOR-SOME-a; or FOR-ALL-a

but you can do

template<typename T, typename A>
concept FooHelper = requires(T t, A a) { t.func(a); };

template<typename T>
concept Foo = FooHelper<T, int> || FooHelper<T, short> || FooHelper<T, char>;
    // or, use &&