13

我一直在尝试来自 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::stringDrawable概念匹配——这是我预料到的,因为在调用draw()时,适当的函数在范围内static_assert

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

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

4

2 回答 2

3

该问题与 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可以表示全局范围),应在其在其所在的块中使用之前声明used or 在其封闭块之一(6.3)中,或者,应在其在命名空间中使用之前声明N...

由于该概念与功能有关,因此适用上述段落。

于 2016-05-05T01:41:23.070 回答
-1

因为,需要声明上面的函数,以便所有使用它的函数都需要知道它。

在一个类中,函数在头文件中声明。如果它们不是成员,则需要在使用之前声明它们。这是因为编译器从上到下读取,只有在看到声明时才知道函数。

如果您交换概念代码和绘图代码,它也应该可以工作。

于 2016-04-20T22:07:51.313 回答