不受约束的 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 &&
我可以在概念的 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 是否可能支持这样的事情,根据我从
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 &&