首页
学习
活动
专区
圈层
工具
发布
首页
学习
活动
专区
圈层
工具
MCP广场
社区首页 >问答首页 >如何强制C++从全局命名空间中选择函数?

如何强制C++从全局命名空间中选择函数?
EN

Stack Overflow用户
提问于 2015-12-03 13:19:15
回答 4查看 1.7K关注 0票数 4

我有一个容器,希望依赖使用我的库的人来确保底层value_type (在下面的示例中是pow())可以使用一个函数。我希望编译器在同名成员函数的内部使用该函数,基于它的签名。

我试图创建一个最小的示例:

代码语言:javascript
运行
复制
#include <iostream>
#include <cmath>

using std::pow;

template <typename T>
struct container {
    T value;

    container<T> pow(T const exp) const {
        return {pow(this->value, exp)};
    }
};

int main() {
    container<double> value{81.};
    std::cout << value.value << "^0.25 = " << value.pow(.25).value << '\n';
    return 0;
}

container<>提供了一个pow()方法,该方法应该依赖于全局命名空间中的底层类型中的pow()。

这应该是为了方便使用自定义的类数字类型。也就是说,库用户应该能够定义自己的类型,这些类型与数字一样,并为其类型提供一个pow()函数,以使其与container<>兼容。

问题是,clang和gcc都没有从全局命名空间中获取函数:

代码语言:javascript
运行
复制
c++ -std=c++11 pow.cpp -o pow
pow.cpp:11:28: error: too many arguments to function call, expected single argument 'exp', have 2 arguments
                return {pow(this->value, exp)};
                        ~~~              ^~~
pow.cpp:17:50: note: in instantiation of member function 'container<double>::pow' requested here
        std::cout << value.value << "^0.25 = " << value.pow(.25).value << '\n';
                                                        ^
pow.cpp:10:2: note: 'pow' declared here
        container<T> pow(T const exp) const {
        ^

如果我显式地使用全局命名空间,它将按预期工作:

代码语言:javascript
运行
复制
container<T> pow(T const exp) const {
    return {::pow(this->value, exp)};
}

程序产生预期的输出:

代码语言:javascript
运行
复制
c++ -std=c++11 pow.cpp -o pow
./pow
81^0.25 = 3

这解决了实际问题,但我不知道为什么有必要这样做?签名匹配不应该允许编译器选择正确的函数吗?

EN

回答 4

Stack Overflow用户

发布于 2015-12-03 13:33:55

此问题与模板无关。试试下面的代码:

代码语言:javascript
运行
复制
#include <iostream>
#include <cmath>

using std::pow;

struct container_double {
    double value;

     container_double pow(double const exp) const {
          return {pow(this->value, exp)};
     }
};

int main() {
     container_double value{81.};
     std::cout << value.value << "^0.25 = " << value.pow(.25).value << '\n';
     return 0;
}

这将产生与您的错误相同的错误。问题是(引用的答案):

名为foo的成员函数在类范围内找到,然后名称查找将停止,因此全局版本foo永远不会被考虑为重载解析,即使全局版本在这里更合适。这是一种隐藏的名字。

或者来自 one:

通常,当作用域被嵌套时,在内部作用域中声明的任何名称都会隐藏在内部作用域中使用同名的任何实体。因此,在本例中,当在类范围中使用时,类中声明的名称将隐藏在封闭命名空间中声明的名称。

最后,另一个类似的行为是从基类重写派生类隐藏其他过载中的函数。

票数 2
EN

Stack Overflow用户

发布于 2015-12-03 13:22:01

只需使用::

代码语言:javascript
运行
复制
template <typename T>
struct container {
    T value;

    container<T> pow(T const exp) const {
       return {::pow(this->value, exp)};
    }
};

在没有::的情况下,只测试结构的pow是否匹配。如果没有,如果您犯了错误,您将使用一个全局函数,而不会注意到它。

票数 0
EN

Stack Overflow用户

发布于 2015-12-03 14:36:26

全局pow由容器::pow隐藏,名称隐藏规则在3.3.10第1 (*)段中。因此,当名称查找发生时,它是不可见的,因此找不到它,因此它无法参与重载解析。由于重载解析已经是C++中最复杂的部分之一,将外部作用域的名称与其交织在一起可能会导致太多的意外;如果来自任意外部作用域的函数可能涉及特定函数调用的重载解析,那么您可能需要搜索很远的范围,以确定为什么会发生特定的重载解析。

普通的头文件会带来很多程序员不知道的东西进入全局范围。(该规则相当古老,早于决定将所有标准名称放入命名空间std::.但无论如何,我们仍然需要它,因为人们使用指令(不同于使用只引入一个名称的声明)来将大量他们不一定知道的名称引入到一个范围中。

例如,header <algorithm>使用了许多程序员为完全不同的目的广泛使用的几个名称;考虑函数模板std::count(),它有一个名称,许多程序员可能会将其用于循环索引--或者作为一个计算事物的函数。或者考虑函数模板std::min()和std::max()。许多较老的码基都有自己的最小或最大。(虽然这些经常是宏,但我不会进入一个蠕动的蠕虫球。)

票数 0
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/34067114

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档