概念和声明顺序

Tri*_*dle 11 c++ c++-concepts c++17

我一直在试验SVN的GCC中的概念精简版.我遇到了一个问题,我怀疑是因为我缺乏理解,如果有人能指出我正确的方向,我会很感激.我的代码是:

#include <iostream>
#include <string>

// Uncomment this declaration to change behaviour
//void draw(const std::string&);

template <typename T>
concept bool Drawable() {
    return requires (const T& t) {
        { draw(t) }
    };
}

void draw(const std::string& s)
{
    std::cout << s << "\n";
}

int main()
{
    static_assert(Drawable<std::string>()); // Fails
}
Run Code Online (Sandbox Code Playgroud)

在这里,我定义了一个简单的概念,Drawable它旨在要求给定一个类型的参数const T&,函数draw(t)编译.

然后我定义了一个draw(const std::string&)"绘制"字符串的函数cout.最后,我检查是否std::string匹配Drawable概念 - 我预期它会做什么,因为调用draw()时适当的函数在范围内static_assert.

但是,静态断言失败,除非我在概念定义draw(const std::string&) 之前包含声明,并且我不知道为什么.

这是概念的预期行为,还是我做错了什么?

uh *_*per 3

该问题与 ADL 无关,而仅与名称查找有关。GCC 使用的概念草案是 n4377,但我将使用的 C++ 标准草案是 n4140。首先,在深入研究标准之前,我们可以将您的问题转化为我们知道应该有效的形式的 MCVE 。例子:

\n\n
template<typename T> concept bool C =\n  requires (T a, T b) {\n    a + b;\n  };\n
Run Code Online (Sandbox Code Playgroud)\n\n

这是一个简单的要求,[expr.prim.req.simple],用于检查表达式的有效性。重写我们的示例以匹配以下形式:

\n\n
template<typename T> concept bool Drawable = \n  requires (const T& x) { \n    draw(x); \n  };\n
Run Code Online (Sandbox Code Playgroud)\n\n

我们可以看到我们的语法很好。好的,n4377 说什么?

\n\n
\n

[expr.prim.req]/1要求表达式提供了一种简洁的方式来表达对模板参数的要求。需求是可以通过名称查找 (3.4) 或通过检查类型和表达式的属性来检查的需求。

\n\n

[expr.prim.req]/6 需求主体由一系列需求组成。这些要求可能涉及本地参数、模板参数以及从封闭上下文中可见的任何其他声明。...

\n
\n\n

说得通。我们知道封闭上下文是全局命名空间,那么 n4140 说什么?

\n\n
\n

[basic.lookup.unqual]/1 在 3.4.1 列出的所有情况下,将按照每个相应类别中列出的顺序在范围中搜索声明;一旦找到名称的声明,名称查找就会结束。\n 如果未找到声明,则该程序\n 格式错误。

\n\n

函数\xe2\x80\x99s\n declarator-id后面的函数定义中使用的名称是命名空间的成员N(其中,仅出于说明的目的,N可以表示全局范围)\n在使用它的块或其封闭块之一(6.3)中使用之前,或者,应在命名空间中使用之前声明N...

\n
\n\n

由于该概念与功能相关,因此上面的段落也适用。

\n