如何强制C++从全局命名空间中选择一个函数
How do I force C++ to choose a function from the global namespace?
我有一个容器,并希望依靠使用我的库的人来确保函数可用于底层value_type(在下面的示例中为 pow(((。我希望编译器根据其签名在具有相同名称的成员函数中使用该函数。
我试图创建一个最小的例子:
#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;
}
容器<>提供了一个 pow(( 方法,该方法应该依赖于全局命名空间中底层类型提供的 pow((。
这应该便于使用自定义的类似数字的类型。 即,库用户应该能够定义自己的类型,这些类型的行为类似于数字,并为他们的类型提供 pow(( 函数,使其<>容器兼容。
问题是,clang 和 gcc 都没有从全局命名空间中获取函数:
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 {
^
如果我显式使用全局命名空间,它会按预期工作:
container<T> pow(T const exp) const {
return {::pow(this->value, exp)};
}
程序产生预期的输出:
c++ -std=c++11 pow.cpp -o pow
./pow
81^0.25 = 3
这解决了实际问题,但我想知道为什么有必要?签名匹配不应该允许编译器选择正确的函数吗?
在pow
函数中引入std::pow
函数。 这允许编译器在 ADL 失败时回退到std::pow
#include <iostream>
#include <cmath>
template <typename T>
struct container {
T value;
container<T> pow(T const exp) const {
using std::pow;
return {pow(this->value, exp)};
}
};
int main() {
container<double> value{81.};
std::cout << value.value << "^0.25 = " << value.pow(.25).value << 'n';
return 0;
}
现场示例
这与构建自定义交换函数时要执行的操作相同。 您可以在此处看到它与具有自己pow
的类一起工作
为那些不了解查找的人编辑。了解两者之间的区别很重要
T func(T a, T b)
{
using std::pow;
return pow(a,b);
}
和
T func(T a, T b)
{
return std::pow(a,b);
}
后者总是调用std::pow()
,如果T
无法转换为 double
,则会失败(如果<complex>
被#include
d(,则std::complex<double>
(。前者将使用ADL来查找最佳匹配pow()
函数,这可能是std::pow
。
此问题与模板无关。试试这段代码:
#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 进行重载解析,即使全局版本在这里更合适。这是一种名字隐藏。
或者从这个:
通常,当作用域嵌套时,在内部作用域中声明的任何名称都会在外部作用域中隐藏具有相同名称的任何实体。因此,在这种情况下,在类作用域中使用时,在类中声明的名称将隐藏在封闭命名空间中声明的名称。
最终,另一个类似的行为是重写派生类中的函数会隐藏基类中的其他重载。
只需使用::
template <typename T>
struct container {
T value;
container<T> pow(T const exp) const {
return {::pow(this->value, exp)};
}
};
如果没有::
则仅测试结构的pow
是否匹配。如果没有,如果你犯了一个错误,你将在不注意的情况下使用全局函数。
简单的答案是:您不会强迫C++从全局命名空间中选择函数。(句号(
相反,您声明与用户定义类型关联的任何功能与类型相同的namespace
,即
namespace foo {
struct bar // the 'value_type'
{
double x;
};
// define functions related to type bar in same namespace
std::ostream& operator<<(std::ostream&s, bar x)
{
return s<<x.x;
}
foo::bar pow(foo::bar x, foo::bar y)
{
return {std::pow(x.x,y.x)};
}
}
什么时候
template <typename T>
struct container {
T value;
container<T> pow(T const&exp) const
{
using std::pow;
return {pow(this->value, exp)};
}
};
通过 ADL 查找 T
= foo::bar
的foo::pow()
,T
= double
的 std::pow()
查找。
int main()
{
container<foo::bar> value{81.};
std::cout << value.value << "^0.25 = "
<< value.pow(foo::bar{0.25}).value << 'n';
}
全局 pow 由 container::p ow 隐藏,名称隐藏规则位于 3.3.10 第 1 段 (*( 中。因此,当名称查找发生时,它不可见,因此找不到它,因此它不能参与重载解析。由于过载解析已经是C++中最复杂的部分之一,因此将外部作用域的名称交错在一起可能会导致太多意外;如果来自任意外部作用域的函数可能涉及特定函数调用的重载解析,则可能需要进行广泛搜索才能找出发生特定重载解析的原因。
常见的头文件可以将大量普通程序员不知道的东西带入全局范围。(该规则非常古老,早于将所有标准名称放在命名空间 std 中的决定::...但是我们仍然需要它,因为人们使用USING指令(不同于使用声明,只引入一个名称(将大量他们不一定知道的名称带入一个范围。
例如,标头<algorithm>
使用多个名称,这些名称被许多程序员广泛用于完全不同的目的;考虑函数模板 std::count((,它有一个许多程序员可能用于循环索引的名称 - 或作为计数事物的函数。或者考虑函数模板 std::min(( 和 std::max(( 。许多较旧的代码库都有自己的最小值或最大值。(虽然这些通常是宏,但我不会进入一团蠕动的蠕虫。
- 函数向量_指针有不同的原型,我可以构建一个吗
- 为什么在没有显式默认构造函数的情况下,将另一个结构封装在联合中作为成员的结构不能编译
- 创建一个函数以在输入为负数或零时输出字符串.第一次执行用户定义的函数
- 基于另一个成员参数将函数调用从类传递给它的一个成员
- 如何仅为一个函数添加延迟
- 构造函数正在调用一个使用当前类类型的函数
- C++-试图将函数指针推回到另一个CPP文件中的矢量时出错
- 有一个打印语句的函数是一种糟糕的编程实践吗
- 有没有什么方法可以使用一个函数中定义的常量变量,也可以由c++中同一程序中的其他函数使用
- 输入到文件并输出到另一个文件,并将流文件传递给函数
- 我不明白为什么我声明一个空的内部结构并将其传递给构造函数
- 如何创建函数管道,以便函数一个接一个地运行?
- 如何巧妙地编写两个函数——一个用于检查是否存在解决方案,另一个用于获取所有解决方案
- 在c++中的复制构造函数/一个声明语句中的初始化的延续中使用chain方法
- C :基类调用自己的虚拟函数 - 一个反图案
- 如何在这个交换函数(一个单独的链表)中找到错误
- 两个相同的函数(一个使用模板模式,另一个不使用)
- 你怎么能一次给一个函数一个参数呢
- 为什么要做两个函数?(一个是非const,另一个是const)
- 当代码在其他地方使用时,如何保证函数一个接一个地被调用