简体   繁体   English

C++20 概念需要运算符重载与用户定义的模板运算符重载相结合 function

[英]C++20 concepts require operator overloading combine with user-define template operator overloading function

case 1情况1

Consider the following concept which requires the value_type of a range R is printable:考虑以下concept ,它requires R rangevalue_type是可打印的:

#include <iostream>
#include <iterator>

template <class R, typename T = std::ranges::range_value_t<R>>
concept printable_range = requires(std::ostream& os, const T& x) { os << x; };

It works fine with std::vector<int> on different three compliers:它适用于不同的三个编译器上的std::vector<int>

static_assert(printable_range<std::vector<int>>);

but if I define a template operator<< function with any type x after concepts define:但是,如果我在concepts定义后定义了具有任何类型x的模板operator<< function:

std::ostream& operator<<(std::ostream& os, const auto& x) { return os << x; }

GCC and MSVC can pass the following assert but Clang fails : GCC 和 MSVC 可以通过以下断言,但 Clang失败

static_assert(printable_range<std::vector<std::vector<int>>>);

Which compiler should I trust?我应该信任哪个编译器? It seems like a Clang bug.这似乎是一个 Clang 错误。

case 2案例2

Weirdly, If I define a custom struct S with operator<< support before the concept printable_range define:奇怪的是,如果我在定义printable_range concept之前定义了一个带有operator<<支持的自定义结构S

struct S{};
std::ostream& operator<<(std::ostream& os, const S&) { return os; }

Same assert fails with MSVC, but GCC still accept it: MSVC 的相同断言失败,但 GCC 仍然接受它:

static_assert(printable_range<std::vector<std::vector<int>>>);

Is it an MSVC bug?它是一个 MSVC 错误吗?

case3案例3

If I transform the operator<< function into a named function print , then all the compiler fails on the second assert.如果我将operator<< function 转换为名为 function print ,那么所有编译器都会在第二个断言上失败 This surprised me since it looks equivalent to case 1, the key points here are the member function vs. free function or operator overloading function vs. free function ? This surprised me since it looks equivalent to case 1, the key points here are the member function vs. free function or operator overloading function vs. free function ?

void print(int x) { std::cout << x; };

template <class R, typename T = std::ranges::range_value_t<R>>
concept printable_range = requires(const T& x) { print(x); };

void print(auto x) { std::cout << x; };

static_assert(printable_range<std::vector<int>>);
static_assert(printable_range<std::vector<std::vector<int>>>); // failed!

Which compiler should I trust?我应该信任哪个编译器? It seems like a Clang bug.这似乎是一个 Clang 错误。

This is a GCC/MSVC bug.这是一个 GCC/MSVC 错误。 Name lookup for os << x will perform argument-dependent lookup to find any other associated operator<< s, but the associated namespaces here are just std . os << x的名称查找将执行与参数相关的查找以查找任何其他关联的operator<< s,但此处关联的命名空间只是std Your operator<< is not in namespace std , so lookup should not find it, so there should be no viable candidates.您的operator<<不在namespace std中,因此查找不应该找到它,所以应该没有可行的候选人。

The fact that GCC and MSVC do so is a bug. GCC 和 MSVC 这样做的事实是一个错误。

The issue with GCC is that its lookup with operators, specifically, just finds more things than it should (see 51577 , thanks T.C.). GCC 的问题在于它与操作员的查找,具体来说,只是找到了比它应该的更多的东西(参见51577 ,感谢 T.C。)。 That's why it can find the operator<< but not the print .这就是为什么它可以找到operator<<而不是print的原因。

Really, these are the same example, just with a different name ( print vs operator<< ) and they should have the same behavior.确实,这些是同一个示例,只是名称不同( print vs operator<< ),它们应该具有相同的行为。

Clang is correct. Clang 是正确的。 This is the usual two-phase lookup rule that GCC is known to handle incorrectly for operators (and MSVC is also not exactly known for proper two-phase lookup support, though they are getting better).这是通常的两阶段查找规则,已知 GCC 对操作员的处理不正确(MSVC 也不完全以正确的两阶段查找支持而闻名,尽管它们正在变得更好)。

Ordinary unqualified lookup for operator<< only occurs from the definition context and finds nothing.operator<<的普通非限定查找只发生在定义上下文中,什么也找不到。 Argument-dependent lookup can't find the operator<< in the global namespace either, since the global namespace is not an associated namespace of std::vector<int> .依赖于参数的查找也无法在全局命名空间中找到operator<< ,因为全局命名空间不是std::vector<int>的关联命名空间。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM