为什么编译器会检查这个概念并生成错误?

问题描述 投票:0回答:1

编译以下代码会产生:

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>)
。对于任何其他类型,似乎都是这样工作的。

备注:

c++ c++20 c++-concepts
1个回答
0
投票

使用两阶段名称查找,在

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
- 但请记住,我们已经在实例化它了。因此存在概念依赖于其自身的错误。

© www.soinside.com 2019 - 2024. All rights reserved.