我一直在尝试使用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
}
这里我定义了一个简单的概念Drawable
,它旨在要求给定一个const T&
类型的参数,函数draw(t)
编译。
然后我定义了一个函数draw(const std::string&)
,它将字符串“绘制”到cout
。最后,我检查std::string
是否与Drawable
概念匹配 - 这是我预期的概念,因为调用draw()
时适当的static_assert
函数在范围内。
然而,静态断言失败,除非我在概念定义之前包含draw(const std::string&)
的声明,并且我不知道为什么。
这是概念的预期行为,还是我做错了什么?
答案 0 :(得分:1)
问题与ADL无关),但仅与名称查找有关。 GCC使用的概念草案是n4377,但我将使用的C ++标准草案是n4140。首先,在深入了解标准之前,我们可以将您的问题转变为我们知道假设的形式的MCVE。例如:
template<typename T> concept bool C =
requires (T a, T b) {
a + b;
};
这是一个简单的要求,[expr.prim.req.simple],它检查表达式的有效性。重写我们的示例以匹配表单:
template<typename T> concept bool Drawable =
requires (const T& x) {
draw(x);
};
我们可以看到我们的语法很好。好吧,n4377说什么?
[expr.prim.req] / 1 requires-expression 提供了一种简洁的方法 表达对模板参数的要求。要求是一个要求 可以通过名称查找(3.4)或通过检查类型的属性来检查 和表达。
[expr.prim.req] / 6需求主体由一系列序列组成 要求。这些要求可能涉及本地参数, 模板参数,以及从中可见的任何其他声明 封闭的背景。 ...
有道理。我们知道封闭上下文是全局命名空间,所以n4140说的是什么?
[basic.lookup.unqual] / 1在3.4.1中列出的所有情况下,范围 按照每个中列出的顺序搜索声明 各自的类别;名称查找在声明后立即结束 找到了这个名字。如果没有找到声明,程序就是 不良形成。
函数定义后使用的名称 declarator-id ,它是命名空间
N
的成员(其中,仅出于展示的目的,N
可以表示全局范围)应为 在使用它之前或在其中一个中使用之前声明 其封闭块(6.3)或应在其使用前声明 名称空间N
...
由于概念属于该功能,上述段落适用。
答案 1 :(得分:-1)
因为,需要声明上面的函数,以便使用它的所有函数都需要知道它。
在类中,函数在头文件中声明。如果他们不是会员,那么他们需要在使用之前申报。这是因为编译器从上到下读取,只有在看到声明时才知道函数。
如果你交换概念代码和绘图代码,它也应该有效。