2014-01-14 2 views
1

주어진 형식이 함수의 사용 가능한 오버로드에 인수로 전달 될 수 있는지 확인하기위한 템플릿 코드를 작성하고 있습니다. 아래 예제에서는 log 함수를 사용했지만 수학 라이브러리의 다른 코드에서도이 코드를 시도했지만 결과는 같습니다. 아이디어는 함수 오버로딩과 sizeof 연산자를 사용하여 해당 유형이 문제의 함수 (이 예에서는 로그)로 합법적으로 전달 될 수있는 경우를 구별하는 것입니다.std :: string에 대한 오버로드가 템플릿 코드에서 감지되지 않았습니다.

제대로 작동하면 '유형'을 합법적으로 로그에 전달할 수있는 경우 sizeof(overload<type>(NULL)) == sizeof(True)이고 그렇지 않은 경우 sizeof(overload<type>(NULL)) == sizeof(False)이됩니다. 이는 대부분의 유형에서 작동하는 것으로 보이지만 std::string에서는 실패합니다.

여기에 실패 정확히 방법은 다음과 같습니다 우리가 정상적으로

정상적인 상황에서 우리는 sizeof(overload<std::string>(NULL)) == sizeof(False) 있습니다. 그러나 문자열을 사용하는 로그의 과부하를 선언하면 여전히 논리의 sizeof (True) 분기를 트리거하지 않습니다. 사실 실제로는 log(std::string) 함수를 선언하고 싶지는 않습니다.이 코드를 테스트하여 가능한 모든 오버로드를 감지 할 수 있는지 확인합니다.

처음에는 제대로 된 과부하를 감지하지 못했지만 사용자 정의 클래스 (아래 예제의 'MyClass')로 시도했을 때 제대로 작동했습니다 : log(MyClass)이 선언되었을 때 sizeof(True)이 생성되었지만, 그렇지 않으면 sizeof (False)입니다.

#include <iostream> 
#include <math.h> 

template<int> 
struct TakesInt{}; 


struct True 
{ 
}; 

struct False 
{ 
    // guarantees that sizeof(False) != sizeof(True) 
    True array[2]; 
}; 


// takes anything; fall back if no match can be found 
template<typename T> 
False overload(...); 

// takes a specific type; does not actually call log 
template<typename T> 
True overload(TakesInt<sizeof(log(T()))>*); 

// As a test, this is an overload of log that takes a string. 
// I don't actually want to implement this, but it should make the compiler 
// think that a string is a valid argument. 
double log(std::string); 


// a placeholder for user defined class; could really be anything, 
// like an arbitrary number class 
struct MyClass{}; 

// declaring log for the arbitrary class above 
// note that this is the same as for the log(std::string) 
// if one works, the other should 
double log(MyClass); 

int main() 
{ 
    std::cout << sizeof(True) << '\t' << sizeof(False) << std::endl; 
    std::cout << sizeof(overload<std::string>(NULL)) << std::endl; 
    std::cout << sizeof(overload<double>(NULL)) << std::endl; 
    std::cout << sizeof(overload<MyClass >(NULL)) << std::endl; 
    return 0; 
} 
+0

소리가 이름 조회 문제와 유사합니다. 'True overload (TakesInt *);'의 정의 시점에서 부적합 조회를 통해'double log (std :: string); ' MyClass는 인스턴스화 시점에서 ADL을 통해 발견됩니다. 난 그냥'overload' 전에'log (std :: string)'의 오버로드를 넣었을 때 확인했다. 그것은 정규화되지 않은 조회를 통해 발견 될 것이다 : [Live example] (http : //coliru.stacked-crooked.co.kr/a/17d44cadd598a97c) – dyp

답변

2

여기 승 SFINAE 산만 O/같은 문제가있다 :

출력
#include <iostream> 

namespace ns 
{ 
    struct string {}; 
} 

void bar(...) { std::cout << "void bar(...)\n"; } 

template<class T> 
void foo() 
{ 
    T x{}; 
    bar(x); 
} 

void bar(ns::string) { std::cout << "void bar(ns::string)\n"; } 

int main() 
{ 
    foo<int>(); 
    foo<ns::string>(); 
} 

: 종속 함수 이름

 
void bar(...) 
void bar(...) 

조회를 수행한다 :

  • definiti의 시점에서 (순수한) 무조건적인 조회로서

따라서 인스턴스화의 관점에서 (순수) 인자 의존적 조회 등

  • 에, 다음 예는 다르다 :

    #include <iostream> 
    
    namespace ns 
    { 
        struct string {}; 
    } 
    
    void bar(...) { std::cout << "void bar(...)\n"; } 
    
    template<class T> 
    void foo() 
    { 
        T x{}; 
        bar(x); 
    } 
    
    namespace ns 
    { 
        void bar(ns::string) { std::cout << "void bar(ns::string)\n"; } 
    } 
    
    int main() 
    { 
        foo<int>(); 
        foo<ns::string>(); 
    } 
    

    출력 :

     
    void bar(...) 
    void bar(ns::string) 
    

    std::string 상기 들어 연관된 네임 스페이스는 std입니다. 전역 네임 스페이스는 이 아니며이 아니며 OP 코드에서 검색되지 않습니다. 그러므로 이후에 과부하가 으로 선언되면 템플릿 정의를 찾을 수 없습니다.

    N.B. 오버로드를 네임 스페이스 std에 삽입하지 마십시오. 이렇게하면 [namespace.std]/1에 따라 정의되지 않은 동작이 발생합니다.

  • 관련 문제