2016-10-17 5 views
2

다음과 같은 문제가 있습니다. 나는 다음과 같은 코드를 컴파일 할 때유형 공제가 작동하지 않습니다.

template< typename T > 
T func(T t) 
{ 
    return t; 
} 

template< size_t N, typename T > 
void foo(std::function< T(T) > func) 
{ 
    // ... 
} 

int main() 
{ 
    foo<3>(func<float>); 

    return 0; 
} 

나는 오류 얻을 : 나는

template< typename T > 
T func(T t) 
{ 
    return t; 
} 

template< size_t N, typename T > 
void foo(std::function< T(T) > func) 
{ 
    // ... 
} 

int main() 
{ 

    std::function< float(float) > input_func = func<float>; 
    foo<3>(input_func); 

    return 0; 
} 

에 고정 할 때, 그러나

no matching function for call to 'foo' 
     foo<3>(func<float>); 
     ^~~~~~ 
/Users/arirasch/WWU/dev/xcode/tests/tests/main.cpp:18:10: note: candidate template ignored: could not match 'function<type-parameter-0-1 (type-parameter-0-1)>' against 'float (*)(float)' 
    void foo(std::function< T(T) > func) 

을 즉, 나는의 입력 기능을 선언 할 때 foostd::function< float(float) >으로 명시 적으로 지정하면 컴파일이 성공적으로 완료 될 수 있습니다.

사람은 (내 첫 번째 코드 예제에 따라) 대신

std::function< float(float) > input_func = func<float>; 
foo<3>(input_func); 

input_func의 종류가 명시 적으로 어디를 명기해야한다 단순히 foo<3>(func<float>); 같은 것을 쓸 수 있도록 내가 대안으로 내 코드를 관념 할 수있는 방법을 알고 있나요?

미리 감사드립니다.

+1

기능은'표준 : function's 수 없습니다. –

답변

3

유형 추론은 추론 할 수 없기 때문에 단순히 작동하지 않습니다. 유형 공제는 대부분의 경우 유형 및 기타 템플리트 매개 변수와 간단하게 일치합니다. 그러나 C++의 어두운 구석에는 펑키 규칙이있는 공제를 다루지 만,이 대답을 위해이 규칙을 사용하지 않을 것입니다.

template<typename T> 
void test(std::vector<T>); 

test(std::vector<int>{1, 2, 3, 4, 5, 6}); 

이 컴파일러에 쉽게 :

컴파일러가 템플릿 인수를 추론 할 수있는 예이다. 그것은 T의 벡터가 필요합니다. 여러분은 그것을 정수 벡터로 만듭니다. T는 int 여야합니다.

template<typename T> 
void test(std::function<T(T)>); 

int someFunc(int); 

test(someFunc); 

컴파일러 경기를 수행 할 수 없습니다

그러나, 귀하의 경우, 일이 더 많은 물건이있다. 직접 시도해보십시오. 을 입력하면 두 유형이 동일하게됩니다 : int(*)(int) ~ std::function<T(T)>. 실제로 벡터 버전은 쉬운 일치 인 반면, 두 유형을 동일하게 만들 수있는 T은 없습니다.

당신은 내게 말할 것입니다 : "그러나 ... 함수에 대한 포인터는 std :: convert로 바뀔 수 있습니다!" 예, 컨버터블입니다. 그러나 어떤 변환을하기 전에 컴파일러 을 가지고 무엇이 T인지 찾아야합니다. T이 없으면 포인터를 함수에서 어떤 클래스로 변환합니까? 많은 클래스? T마다 일치합니까? 당신의 기능이 전환 가능한 여러 가지 가능성이 있습니다.


어떻게하면 되나요? std::function은 잊어 버려야합니다. 그냥 T을 받으십시오.

template<typename T> 
T func(T t) { 
    return t; 
} 

template<size_t N, typename T> 
void foo(T func) { 
    // ... 
} 

int main() 
{ 
    foo<3>(func<float>); 

    return 0; 
} 

이 예제가 어떻게 작동하는지주의하십시오. 전환이없고 std::function 건도 없으며 상상할 수있는 모든 통화 가능 코드로 작업 할 수 있습니다!

모든 유형을 수락 하시겠습니까? 걱정 마세요! 매개 변수 유형은 템플릿이받은 매개 변수로 수행 할 수있는 것을 표현하는 나쁜 방법입니다. 으로 제한해야합니다. 그 표현은 다른 사람들에게 T을 어떻게 사용할 것인지 그리고 어떤 인터페이스 T이 필요한지를 알려줍니다. BTW, 우리가 sfinae 호출이 예에서

template<size_t N, typename T> 
auto foo(T func) -> void_t<decltype(func(std::declval<int>()))> { 
    // ... 
} 

을, 당신은 int로 호출 할 func을 제한합니다. 아직 C++ 17 컴파일러가없는 경우

,이 같은 void_t을 구현할 수 있습니다

template<typename...> 
using void_t = void; 
+0

"유형 차감은 간단한 일치입니다 ..."음, 아니. 그것이 일어나는 장소의리스트를 들여다 보면, 그리고 어떤 추측 컨텍스트가 존재합니다. 그것은 C++ 언어에 대한 성서입니다. – MSalters

+0

참. 내 대답을 편집 할게. 지적 해 주셔서 고마워요. –

4

여기서 문제는 컴파일러가 std::function<U(U)> 인스턴스에 T(*)(T)을 사용할 수있는 생성자가 있는지 확인하기 위해 오버로드 확인을 수행해야한다는 것입니다. 즉, 각각 여러 개의 유형이있을 수 있으며 여러 유형이있을 수 있습니다 귀하의 input_func 걸릴 수 있습니다.

이제 표준 보면, 당신은 std::function에 지정된 이러한 과부하가 없다는 것을 찾을 수 있지만, 오버로드 확인 규칙들이하든, 모든 템플릿에 대해 동일 std::, boost:: 또는 ACME::에서. 컴파일러는 템플릿을 인스턴스화하여 변환 시퀀스를 찾지 않습니다.

완벽한 일치를 제공하면 전환 순서가 필요하지 않습니다. 변환 순서가 필요없는 정확히 하나의 대상 유형이 있으며 컴파일러가이 유형을 추론합니다. 이 특별한 경우

, 당신은 함수 포인터와 std::function 사이의 관계에 대해 알고, 또한 특정 제한에 대해 동일한 유형 (NO T(*)(U))을 반환하는 단일 기능을 가지고 있어야 있도록 과부하를 추가 할 수

template< size_t N, typename T > 
void foo(T(*func)(T)) 
{ 
    return foo<N>(std::function<T(T)>(func)); 
} 
2

fd를 std :: function에 캐스트하면 명시 적으로 문제가 해결됩니다. 예 : 아래 코드가 작동합니다.

template< typename T > 
T func(T t) 
{ 
    return t; 
} 

template<typename T> 
using FuncType = std::function<T(T)>; 

template< size_t N, typename T > 
void foo(FuncType<T> func) 
{ 
    // ... 
} 

int main() 
{ 
    func<float>(1.0); 
    foo<3>(FuncType<float>(func<float>)); 

    return 0; 
} 
관련 문제