为什么clang找不到在调用站点之前声明的函数
Why clang does not find a function declared prior to the call site?
我想为simd类型提供一些sqrt包装函数,这样它们就可以从模板中与std::sqrt一起使用。
现在我的问题是,它们不知何故是看不见的。只能使用std中定义的。
这是代码的高度简化部分:
#include <cmath>
#include <pmmintrin.h>
using float_simd = __m128;
using double_simd = __m128d;
float_simd sqrt(float_simd a) { return _mm_sqrt_ps(a); }
double_simd sqrt(double_simd a) { return _mm_sqrt_pd(a); }
template <typename T>
void do_fancy(T val)
{
using std::sqrt;
auto ret = sqrt(val);
(void)ret;
}
int main() {
double testDouble = 1.0;
float testFloat = 1.0f;
double_simd testSimdDouble;
float_simd testSimdFloat;
do_fancy(testDouble);
do_fancy(testFloat);
do_fancy(testSimdDouble);
do_fancy(testSimdFloat);
return 0;
}
现在clang给出了这个:
main.cpp:14:16: error: call to function 'sqrt' that is neither visible in the template definition nor found by argument-dependent lookup
auto ret = sqrt(val);
^
main.cpp:25:5: note: in instantiation of function template specialization 'do_fancy<__attribute__((__vector_size__(2 * sizeof(double)))) double>' requested here
do_fancy(testSimdDouble);
^
main.cpp:8:13: note: 'sqrt' should be declared prior to the call site
double_simd sqrt(double_simd a) { return _mm_sqrt_pd(a); }
^
main.cpp:14:16: error: call to function 'sqrt' that is neither visible in the template definition nor found by argument-dependent lookup
auto ret = sqrt(val);
^
main.cpp:26:5: note: in instantiation of function template specialization 'do_fancy<__attribute__((__vector_size__(4 * sizeof(float)))) float>' requested here
do_fancy(testSimdFloat);
^
main.cpp:7:12: note: 'sqrt' should be declared prior to the call site
float_simd sqrt(float_simd a) { return _mm_sqrt_ps(a); }
^
它说,simd-sqrt函数"应该在调用站点之前声明",但我认为它们是。
我在网上搜索了一下,但不幸的是,我只发现了一些案例,其中呼叫和声明的顺序实际上是错误的。
我刚刚评论了using std::sqrt
,一切都很好。我不明白……它现在怎么能找到std::sqrt的?
我在macOS上使用自制软件的clang 3.9.1。
using std::sqrt;
在函数体中添加了一个sqrt
的声明,因此函数的名称查找会找到该声明,而不会在封闭范围中考虑函数体之外的声明。
这是"名称隐藏"的一种形式,它是C++的一种属性,其中一个作用域中的名称"隐藏"外部作用域中具有相同名称的实体。之所以会发生这种情况,是因为编译器从最内部的作用域开始查找名称,然后只有在没有匹配项的情况下才会尝试封闭作用域,直到到达最外部(即全局)作用域。因此,一旦在给定范围内找到一个或匹配的名称,它就会停止搜索该名称,并且不会看到外部范围内的匹配名称。
在代码中,名称sqrt
是通过引用std::sqrt
函数的using声明在函数体中声明的。名称查找从函数体的作用域开始,查找匹配项,而不在周围的命名空间中查找。
你需要做:
using std::sqrt;
using ::sqrt;
这意味着两组重载(您在全局命名空间中定义的重载和在命名空间std
中定义的<cmath>
标头)都在函数范围中声明,并且都可以通过名称查找找到。现在编译器将在函数范围中找到所有这些重载,重载解析将根据参数类型选择最佳重载。
另一种选择是使用声明将using std::sqrt
移动到全局命名空间,而不是在函数体中。这将把std::sqrt
添加到全局命名空间中,这样就不会隐藏您自己的sqrt
重载。如果函数体中没有using声明,那么在最内部的作用域中就没有匹配项,因此编译器将在封闭作用域中查找,即全局命名空间。在这个范围内,它会找到所有重载,并且重载解决方案会选择最好的一个。
另一种选择是用<math.h>
替换<cmath>
并移除using std::sqrt;
。这将确保sqrt
的标准库版本在全局命名空间中声明,而不是在命名空间std
中声明,因此您不需要using std::sqrt;
能够将其称为不合格。
正如您在下面的注释中所指出的,如果您只是注释掉using声明,它可能也会起作用,但是这是不可移植的,并且不能保证起作用。它恰好与您使用的编译器一起工作,因为<cmath>
同时声明了std::sqrt
和::sqrt
(因此它相当于在全局命名空间中具有using std::sqrt;
),但并非所有编译器都这样做。为了保证在全局命名空间中获得::sqrt
,应该将using std::sqrt;
放在全局命名空间或包含<math.h>
。
- C++:为什么允许在另一个函数中声明函数,而不允许在函数定义中声明?
- 在c++中在类外声明函数有什么好处
- 使用 #define 声明函数
- 在静态库中声明函数,在使用该相同库的应用程序中定义它
- 如何强制编译器在 C/C++ 本身中声明函数?
- 如果您只需要在 .h 文件中声明函数.cpp是否需要在 .h 文件中声明函数?
- C++:<sys/sysctl.h> 无法声明函数CTL_HW和HW_NCPU
- 尝试声明函数的局部变量,但得到范围错误
- 如何在C++模板中声明函数
- 如何在另一个文件的类中声明函数
- 使用非类型模板参数正向声明函数模板
- 在此范围错误中未声明函数错误
- 当我们不能声明函数内联(GCC 编译器)时?
- 未在此作用域中声明函数,即使存在头文件也是如此
- 无法声明函数中的模板类型别名
- 单个CPP文件中多次声明函数声明可以吗?
- 编译一个支持VBA中声明函数的dll
- 使用从外部参数包中获取的参数类型声明函数
- 使用类成员正确地声明函数
- 在函数内重新声明函数