2010-04-19 1 views
23

이것은 매우 간단한 설명이 될 것입니다. 그러나 틀린 경우를 대비하여 가능한 한 많은 백 스토리를 제공 할 것입니다. 너무 장황한 것에 대해 진지하게 사과드립니다. 나는 gcc4.5를 사용하고 있으며, C++ 0x 지원은 아직 다소 실험적이지만, 내가 본 행동에 대한 비 버그 관련 이유가 있다는 가정하에 행동 할 것입니다.가변적 인 함수에 대한 반환 유형을 재귀 적으로 구축 할 때의 이상한 동작

나는 variadic 함수 템플릿을 실험하고있다. 최종 목표는 std::pair 중에서 죄수 목록을 작성하는 것이 었습니다. 그것은 커스텀 타입이 아니라 쌍 객체 쌍을 의미합니다. 리스트를 구성하는 함수는 재귀 호출의 결과에 종속적 인 궁극적 인 반환 값을 갖는 어떤 방식으로 재귀 적이어야합니다. 추가 된 트위스트로서 연속 매개 변수가 목록에 삽입되기 전에 함께 추가됩니다. 따라서 [1, 2, 3, 4, 5, 6]을 통과하면 최종 결과는 {1 + 2, {3 + 4, 5 + 6}}이어야합니다.

나의 초기 시도는 상당히 순진했다. 두 가지 오버로드가있는 빌드, 함수. 하나는 두 개의 동일한 매개 변수를 사용하여 간단히 합계를 반환했습니다. 다른 하나는 두 개의 매개 변수와 하나의 매개 변수 팩을 사용했습니다. 반환 값은 두 개의 set 매개 변수의 합계와 재귀 호출로 구성된 쌍이었습니다. 돌이켜 볼 때, 이것은 분명히 결함이있는 전략이었습니다. 왜냐하면 반환 유형을 알아 내려고 시도 할 때 함수가 선언되지 않았기 때문에 비 재귀 버전으로 해결할 수밖에 없었습니다.

나는 그것을 알고있다. 내가 혼란 스러웠던 곳은 두 번째 반복이었다. 나는 그 함수들을 템플릿 클래스의 정적 멤버로 만들기로 결정했다. 함수 호출 자체는 매개 변수화되지 않지만 대신 전체 클래스가 호출됩니다. 필자의 가정은 재귀 함수가 반환 형식을 생성하려고 할 때 자체 정적 함수를 사용하여 구조의 완전히 새로운 버전을 인스턴스화하고 모든 것이 자체적으로 작동한다는 가정이었습니다.

결과였다

기분을 상하게하는 코드 : "오류 BuildStruct<double, double, char, char>::Go(const char&, const char&)에 호출 일치 기능 없음"

static auto Go(const Type& t0, const Type& t1, const Types&... rest) 
    -> std::pair<Type, decltype(BuildStruct<Types...>::Go(rest...))> 

내 혼란 BuildStruct에 매개 변수가 항상 동일해야한다는 사실에서 온다 형식을 BuildStruct::Go에 전송 된 인수로 사용하지만 오류 코드에서 처음 두 개의 이중 매개 변수가 누락되었습니다. 내가 여기서 무엇을 놓치고 있니? 정적 함수가 어떻게 선택 될지에 대한 나의 초기 가정이 틀렸다면, 함수를 찾지 않고 잘못된 함수를 호출하려고하는 이유는 무엇입니까? 그것은 단지 유형을 섞일 것 같아요. 왜 그런지 설명 할 수 없어요. 초기 호출에 추가 매개 변수를 추가하면 실패하기 전에 항상 마지막 단계로 넘어 가서 재귀 자체가 적어도 부분적으로 작동합니다. 이것은 초기 시도와 직접적인 대조를 이룬다. 초기 시도는 항상 즉시 함수 호출을 찾지 못했다.

궁극적으로, 나는 처음 두 시도 중 하나와 거의 유사하지 않은 상당히 우아한 해결책으로 궁극적으로 문제를 극복했습니다. 그래서 나는 내가하고 싶은 일을하는 법을 안다. 내가 본 실패에 대한 설명을 찾고 있습니다.

필자의 구두 설명이 충분하지 않았기 때문에 따라야 할 전체 코드. 먼저 코드를 실행하고 자신을 위해 그것을 보도록 강요 받았다면 약간의 상용구. 그런 다음 합리적으로 실패한 최초의 시도와 그렇지 않은 두 번째 시도가 그 것이다.

#include <iostream> 
using std::cout; 
using std::endl; 

#include <utility> 

template<typename T1, typename T2> 
std::ostream& operator <<(std::ostream& str, const std::pair<T1, T2>& p) { 
    return str << "[" << p.first << ", " << p.second << "]"; 
} 

//Insert code here  

int main() { 
    Execute(5, 6, 4.3, 2.2, 'c', 'd'); 
    Execute(5, 6, 4.3, 2.2); 
    Execute(5, 6); 

    return 0; 
} 

비 구조체 용액 :

template<typename Type> 
Type BuildFunction(const Type& t0, const Type& t1) { 
    return t0 + t1; 
} 

template<typename Type, typename... Rest> 
auto BuildFunction(const Type& t0, const Type& t1, const Rest&... rest) 
     -> std::pair<Type, decltype(BuildFunction(rest...))> { 
    return std::pair<Type, decltype(BuildFunction(rest...))> 
        (t0 + t1, BuildFunction(rest...)); 
} 

template<typename... Types> 
void Execute(const Types&... t) { 
    cout << BuildFunction(t...) << endl; 
} 

결과 오류 :

test.cpp: In function 'void Execute(const Types& ...) [with Types = {int, int, double, double, char, char}]': 
test.cpp:33:35: instantiated from here 
test.cpp:28:3: error: no matching function for call to 'BuildFunction(const int&, const int&, const double&, const double&, const char&, const char&)' 

구조체 용액 :

template<typename... Types> 
struct BuildStruct; 

template<typename Type> 
struct BuildStruct<Type, Type> { 
    static Type Go(const Type& t0, const Type& t1) { return t0 + t1; } 
}; 

template<typename Type, typename... Types> 
struct BuildStruct<Type, Type, Types...> { 
    static auto Go(const Type& t0, const Type& t1, const Types&... rest) 
     -> std::pair<Type, decltype(BuildStruct<Types...>::Go(rest...))> { 
    return std::pair<Type, decltype(BuildStruct<Types...>::Go(rest...))> 
       (t0 + t1, BuildStruct<Types...>::Go(rest...)); 
    } 
}; 

template<typename... Types> 
void Execute(const Types&... t) { 
    cout << BuildStruct<Types...>::Go(t...) << endl; 
} 

결과 오류 :

test.cpp: In instantiation of 'BuildStruct<int, int, double, double, char, char>': 
test.cpp:33:3: instantiated from 'void Execute(const Types& ...) [with Types = {int, int, double, double, char, char}]' 
test.cpp:38:41: instantiated from here 
test.cpp:24:15: error: no matching function for call to 'BuildStruct<double, double, char, char>::Go(const char&, const char&)' 
test.cpp:24:15: note: candidate is: static std::pair<Type, decltype (BuildStruct<Types ...>::Go(BuildStruct<Type, Type, Types ...>::Go::rest ...))> BuildStruct<Type, Type, Types ...>::Go(const Type&, const Type&, const Types& ...) [with Type = double, Types = {char, char}, decltype (BuildStruct<Types ...>::Go(BuildStruct<Type, Type, Types ...>::Go::rest ...)) = char] 
test.cpp: In function 'void Execute(const Types& ...) [with Types = {int, int, double, double, char, char}]': 
test.cpp:38:41: instantiated from here 
test.cpp:33:3: error: 'Go' is not a member of 'BuildStruct<int, int, double, double, char, char>' 
+0

지금은 시도 할 수 없지만 지연된 반환 유형 공제가 아직 실패 할 수 있습니다. 두 번째 경우에는'typedef std :: pair <유형, typename BuildStruct :: result_type> result_type;'(그리고 첫 번째 특수화에 적합) 반환 형식을 typedef 할 수 있어야하며 다음을 사용합니다. 'static result_type Go ...); ' – visitor

+0

나는 그것을 시도했지만 결과를 기억하지 못한다고 생각합니다. 나는 집에 갈 때 또 하나의 기회를 줄 것이다. 감사. –

+31

좋은 주인, * 많이 * 읽을 수 있습니다 : –

답변

2

의견을 읽는 중, 이것은 특정 버전의 G ++에서 매우 현지화 된 버그이며, 그 대답은 앞으로도 계속있을 것입니다.

+0

나는 한 달 전에 그 결론에 도달했다. 그래서 대답을 해준 것에 감사한다. –