2017-01-12 2 views
3

simd 유형에 대한 sqrt 래퍼 함수를 ​​제공하여 std :: sqrt와 함께 템플리트에서 사용할 수 있습니다.clang이 호출 사이트보다 먼저 선언 된 함수를 찾지 못하는 이유는 무엇입니까?

이제는 어떻게 든 보이지 않는 문제가 있습니다. 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; 
} 

지금 그 소리는이 제공 :

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에서 자작에서 3.9.1을 사용합니다.

답변

9

using std::sqrt;은 함수 본문에 sqrt의 선언을 추가하므로 함수에 대한 이름 조회는 해당 선언을 찾아 내고 범위를 벗어난 함수 본문 외부의 함수를 고려하지 않습니다.

이것은 한 범위의 이름이 외부 범위에서 같은 이름의 엔터티를 "숨길"수있는 C++의 속성 인 "이름 숨기기"형식입니다. 이것은 컴파일러가 가장 안쪽 범위에서 시작하여 이름을 찾은 다음 일치하는 항목이없는 경우에만 그리고 가장 바깥 쪽 (즉 전역) 범위에 도달 할 때까지 하나를 찾습니다. 따라서 주어진 범위에서 하나 또는 일치하는 것을 찾으면 이름 검색을 중단하고 바깥 범위의 일치하는 이름은 보이지 않습니다.

코드에서 sqrt 이름은 std::sqrt 함수를 참조하는 using 선언에 의해 함수 본문에 선언됩니다. 이름 조회는 해당 함수 본문의 범위에서 시작하여 일치하는 항목을 찾고 주변 네임 스페이스를 조사하지 않습니다.

using std::sqrt; 
using ::sqrt; 

과부하의 두 세트 (전역 네임 스페이스에 정의 된 사람, 그리고 사람 네임 스페이스 std에 정의 된 <cmath> 헤더) 기능 범위에 선언 된 것을 의미 :

당신은 할 필요가 , 둘 다 이름 조회를 통해 찾을 수 있습니다. 이제 컴파일러는 함수 범위에서 모든 오버로드를 찾고 오버로드 해결 방법은 인수 유형에 따라 최상의 오버로드를 선택합니다.

또 다른 옵션은 기능 선언 대신 using std::sqrt 사용 선언을 전역 이름 공간으로 이동하는 것입니다. 전역 이름 공간에 std::sqrt이 추가되어 사용자 자신의 sqrt 오버로드를 숨기지 않습니다. 함수 본문에서 using 선언이 없으면 가장 안쪽 범위에 일치가 없으므로 컴파일러는 전역 네임 스페이스 인 둘러보기 범위를 조사합니다. 이 범위에서 모든 과부하를 찾고 과부하 해결 방법이 최선의 방법을 선택합니다.

다른 옵션은 <cmath><math.h>으로 바꾸고 using std::sqrt;을 제거하는 것입니다.그러면 표준 라이브러리 버전 sqrt이 네임 스페이스 std 대신 전역 네임 스페이스에 선언되므로 using std::sqrt;을 정규화되지 않은 호출 할 필요가 없습니다.

아래의 주석에서 언급했듯이 사용 선언을 주석으로 처리하면 작동하지만 작동하지 않을 수는 있지만 작동 선언이 주석 처리 된 경우에도 작동합니다. <cmath>std::sqrt::sqrt을 선언하므로 (전역 네임 스페이스에 using std::sqrt;이있는 것과 동일하므로) 사용하는 컴파일러에서 작동하지만 모든 컴파일러가이를 수행하지는 않습니다. 전역 네임 스페이스에 ::sqrt을 보장하려면 using std::sqrt;을 전역 네임 스페이스에 넣거나 <math.h>을 포함시켜야합니다.

+2

예. 교과서 이름은 숨어 있습니다. 가끔씩 클래스에서 Base :: foo를 사용하여 석고를 사용하는 것과 같은 이유 (ish). 확실히 C++의 "초보자"에게는 직관적이지 않지만 결국 익숙해집니다. –

+0

좋아요, 맞아요, 이해합니다. 왜'std :: sqrt'를 완전히 사용하는지 설명 할 때 왜 작동하는지 알고 있습니까? – thorink

+0

@ thorink 그 이유는 "해야 할 일 :"대답의 일부가 필요하지 않기 때문입니다. 이름 검색은 C가 표준 라이브러리에서 그렇게 정의한 이후 실제로 전역 이름 공간에있는 sqrt를 검색합니다. – iheanyi