编译以下代码会产生:
error: satisfaction of atomic constraint 'requires(T v) {bar(v);} [with T = T]' depends on itself
。
#include<iostream>
#include<vector>
template<class T>
concept Barable = requires(T v)
{
bar(v);
};
struct Foo
{
template<class T> requires Barable<T>
Foo(T) {};
};
void bar(Foo) {
std::cout << "Foo";
};
void bar(std::vector<Foo>) {
std::cout << "vector";
}
int main()
{
auto v = std::vector<Foo>{};
bar(v);
}
我理解检查这个概念如何导致循环依赖。我不明白的是,为什么在这种设置下,编译器会给出错误。 根据我的理解,它不应该将
bar(Foo)
添加到重载集中并使用 bar(std::vector<Foo>)
。对于任何其他类型,似乎都是这样工作的。
备注:
Foo(T)
,或提供构造函数 Foo(std::vector<Foo>)
可以解决问题int
或std::vector<int>
)可以解决问题使用两阶段名称查找,在
bar
的定义中的名称 Barable
在两个点进行查找 - 在定义点使用普通查找,并在实例化点再次使用参数相关查找(仅 ADL)。由于名称 bar
没有在 Barable
的定义之前声明,因此第一阶段没有找到任何内容。因此,这个概念完全依赖于在实例化点通过 ADL 找到 bar
。
当你稍后做的时候
SomeType arg;
bar(arg);
编译器通过普通查找找到
bar(Foo)
声明,并需要确定它是否可行:它可能是使用bar(Foo{arg})
的转换构造函数调用Foo
。所以它需要实例化那个转换构造函数,这需要实例化Barable<SomeType>
概念。
这可以采用两种方式之一。如果
SomeType
不与全局命名空间关联(例如 std::vector<int>
、普通 int
或 SomeNamespace::SomeType
),则 ADL 不会找到 bar
的任何声明;这样的类型显然不是Barable
。
如果
SomeType
实际上与全局命名空间相关联(例如,在全局命名空间中声明的某些类型 vector<Foo>
的 Baz
、或 std::vector<Baz>
或 Baz
),则 bar(Foo)
找到
。然后,作为实例化 Barable<SomeType>
的一部分,编译器需要为 bar(Foo{v})
类型的 v
实例化 SomeType
- 但请记住,我们已经在实例化它了。因此存在概念依赖于其自身的错误。