11

我没想到这段代码会编译,但确实如此。我的理解是,func(d)它在全局命名空间中查找名为“func”的函数,但也在任何传入参数的命名空间中查找(依赖于参数的查找)

但在这种情况下,参数位于全局命名空间中。那么为什么它会在 ns 命名空间中找到“func”呢?是否有特殊规则说如果参数类型是 typedef 则它使用基础类型的命名空间而不是实际参数的命名空间?

这似乎是真的,但我找不到任何支持这一点的东西......这是预期的行为吗?

namespace ns
{
    struct data {};
    void func(ns::data item) {}
};

// Create an alias "datatype" in the global namespace for ns::data
typedef ns::data datatype;


int main()
{
    datatype d;
    func(d);
}
4

4 回答 4

9

该参数d是本地的maindatatype只是类型的别名,ns::data所以d有 type ns::data

ns::data是命名空间的 [direct] 成员,因此ns命名空间中的此函数ns将被考虑用于 ADL。

于 2012-11-02T10:01:46.127 回答
6

其他答案已经提供了原因,如果不是理由的话:

Atypedef是类型的别名,编译器会将其解析为实际类型。依赖于参数的查找是基于基础类型完成的,而不是 typedef。

这个设计决策的基本原理实际上是 ADL 在语言中的原因。ADL 被添加到语言中以支持运算符重载。在任何其他用例中,用户可以显式声明函数的命名空间,但在运算符重载的情况下,这将导致反直觉的复杂代码:

std::string s("Hi");
std::cout.operator<<(s); // or is it std::operator<<(std::cout,s)??

So the language added rules for lookup to find operators (and functions) in different namespaces, and in particular in the namespace of the arguments to the function. In this case inside std:: in case the operator<< that takes a std::string is not a member of std::cout. The same behavior is extended to all free functions in the same namespace (why not?) allowing the interface of a type to include not only member functions but also free functions in the same namespace.

Now if you focus on this, the purpose is accessing functions that are part of the interface of the type, and those are defined with the type. When you add a typedef in a different namespace you are just creating a shorthand to refer to the original type. All of the functions that were provided with the type (for example operator<<(std::ostream&,MyType)) are in the original namespace, no in the namespace of the typedef. You want ADL to look into the namespace where the real type was defined, not where the alias was created.

于 2012-11-03T01:44:11.523 回答
5

此行为由标准指定(我的重点):

3.4.2 依赖于参数的名称查找 [basic.lookup.argdep]

2 - 对于函数调用中的每个参数类型T,有一组零个或多个关联的命名空间和一组零个或多个关联的类需要考虑。命名空间和类的集合完全由函数参数的类型(以及任何模板模板参数的命名空间)决定。用于指定类型的Typedef 名称和using-declarations不构成此集合。

这有点不幸。这意味着例如代码(改编自ADL,带有来自另一个命名空间的 typedef):

std::vector<int> v;
count(v.begin(), v.end(), 0);

将取决于它的有效性和含义是否std::vector<T>::iterator是 typedefT *或某个类型 in namespace std

于 2012-11-02T10:34:46.833 回答
4

需要注意的主要一点是 atypedef没有引入新类型,而是另一种类型的同义词。d类型也是如此ns::data

现在 ADL 应用并且函数func将在命名空间中找到ns

另外:为了防止 ADL,您可以编写(func)(d).

于 2012-11-02T10:15:07.190 回答