英文:
C++ concept with std::is_convertible_to (missing doc?)
问题
我正在阅读 C++ 概念的文档(https://en.cppreference.com/w/cpp/language/constraints),并遇到了这个第一个示例:
template<typename T>
concept Hashable = requires(T a)
{
{ std::hash<T>{}(a) } -> std::convertible_to<std::size_t>;
};
完整示例在内置的 gcc C++20 中编译,文档中说:
std::hash<T>{}(a) 的表达式可以编译通过,
其结果可以转换为 std::size_t
我检查了 std::is_convertible_to 的签名,它有两个参数(https://en.cppreference.com/w/cpp/concepts/convertible_to):
template <class From, class To>
当只传递一个参数给概念模板时,为什么可以有两个参数?这是文档遗漏还是某种 C++20 概念魔法?
更新:概念规范内部假定有一个隐式参数(传递的类型)。
英文:
I am reading the docs for C++ concepts ( https://en.cppreference.com/w/cpp/language/constraints ) and stumbled upon this very first example:
template<typename T>
concept Hashable = requires(T a)
{
{ std::hash<T>{}(a) } -> std::convertible_to<std::size_t>;
};
The full example compiles with built-in gcc C++20 and the docs say:
the expression std::hash<T>{}(a) compiles and
its result is convertible to std::size_t
I checked the signature of std::is_convertable_to and it has two parameters (https://en.cppreference.com/w/cpp/concepts/convertible_to):
template <class From, class To>
How can a concept-"template" have two parameters when only one argument is passed to it?
Is this omission on the docs side or is it some kind of C++20 concept-magic?
UPD: constraints inside concept specification assume one implicit argument (the passed type).
答案1
得分: 1
当您键入
template<std::convertible_to<std::size_t> X>
void foo(X x);
您只显式传递了一个模板参数。
发生的情况是编译器将其大致转换为
template<class X>
requires std::convertible_to<X, std::size_t>
void foo(X x);
将模板参数列表前置为类型 X
并检查概念。
同样的方式也适用于:
void foo(std::convertible_to<std::size_t> auto x);
其中 x
的类型通过前置到 std::convertible_to<std::size_t>
列表来测试,以及
template<typename T>
concept Hashable = requires(T a)
{
{ std::hash<T>{}(a) } -> std::convertible_to<std::size_t>;
};
{ std::hash<T>{}(a) }
的类型前置到 std::convertible_to<std::size_t>
中以查看它是否通过测试。
您可以在您的概念内添加额外的约束。请确保您的约束是不可分离的,因为最好这样做:
template<class T>
concept Bob = Alice<T> && Eve<T>;
如果 Alice
和 Eve
是可分离的概念,而不是将它们的所有要求合并成一个更大的 requires
块,语言将不会知道这一点。
如果可能的话,当您进行分离时,语言可以知道 Bob
比 Alice
或 Eve
中的任何一个都更受限制。如果您将所有 Alice
和 Eve
的要求合并到一个较大的 requires
块中,语言将无法知道这一点。
英文:
When you type
template<std::convertible_to<std::size_t> X>
void foo(X x);
you only pass one of the template parameters explicitly.
What happens is that the compiler converts this to (roughly)
template<class X>
requires std::convertible_to<X, std::size_t>
void foo(X x);
prepending the template argument lists with the type X
and checking the concept.
The same works with:
void foo(std::convertible_to<std::size_t> auto x);
where the type of x
is tested by prepending it to std::convertible_to<std::size_t>
list, and the same with
template<typename T>
concept Hashable = requires(T a)
{
{ std::hash<T>{}(a) } -> std::convertible_to<std::size_t>;
};
the type of { std::hash<T>{}(a) }
is prepended into std::convertible_to<std::size_t>
to see if it passes the test.
You can add extra constraints within your concept. Be sure to make sure your constraints non-separable, as it is better to do
template<class T>
concept Bob = Alice<T> && Eve<T>;
if Alice
and Eve
are separable concepts, than to make Bob
contain all of their requirements.
If you do this separation when possible, the language can know that Bob
is more-constrained than either Alice
or Eve
. If, on the other hand, you combine all of Alice
and Eve
s requirements into one larger requires
block, the language won't know this.
通过集体智慧和协作来改善编程学习和解决问题的方式。致力于成为全球开发者共同参与的知识库,让每个人都能够通过互相帮助和分享经验来进步。
评论