2014-06-24 5 views
0

나는이 SSCCE처럼 읽는 몇 가지 코드가 있습니다 컴파일하고 잘 작동오버로드 템플릿 함수 선언 순서

#include <map> 
#include <string> 
#include <functional> 

using std::map; 
using std::string; 
using std::function; 
using std::forward; 

template<typename ToType, typename... FromTypes> 
ToType construct(FromTypes&&... fromTypes) { 
    return ToType(forward<FromTypes>(fromTypes)...); 
} 

class Variant { 
public: 
    map<string, Variant> toMap() const; 
}; 

map<string, Variant> Variant::toMap() const { 
    return { 
     {"test", {}}, 
     {"test1", {}}, 
    }; 
} 

// #1 
template <typename MapType> 
MapType variantToMap(Variant const& v) { 
    // I expect an error on the following line because it's referencing the function labeled #4 which has not been declared yet. 
    return variantToMap<MapType>(v, construct<typename MapType::key_type, string>, construct<typename MapType::mapped_type, Variant>); 
} 

// #2 
template <typename MapType> 
MapType variantToMap(Variant const& v, function<typename MapType::key_type(string)> const& keyConvert) { 
    // I expect an error on the following line because it's referencing the function labeled #4 which has not been declared yet. 
    return variantToMap<MapType>(v, keyConvert, construct<typename MapType::mapped_type, Variant>); 
} 

// #3 
template <typename MapType> 
MapType variantToMap(Variant const& v, function<typename MapType::mapped_type(Variant)> const& valueConvert) { 
    // I expect an error on the following line because it's referencing the function labeled #4 which has not been declared yet. 
    return variantToMap<MapType>(v, construct<typename MapType::key_type, string>, valueConvert); 
} 

// #4 
template <typename MapType> 
MapType variantToMap(Variant const& v, function<typename MapType::key_type(string)> const& keyConvert, function<typename MapType::mapped_type(Variant)> const& valueConvert) { 
    MapType res; 
    for (auto pair : v.toMap()) { 
    res[keyConvert(pair.first)] = valueConvert(pair.second); 
    } 

    return res; 
} 

int main() { 
    Variant a; 

    // #1 
    variantToMap<map<string, Variant>>(a); 

    // #2 
    { 
    int counter = 0; 
    variantToMap<map<int, Variant>>(a, [&counter](string) -> int { return ++counter; }); 
    } 

    // #3 
    variantToMap<map<string, int>>(a, [](Variant) -> int { return 42; }); 

    // #4 
    { 
    int counter = 0; 
    variantToMap<map<int, int>>(a, [&counter](string) -> int { return ++counter; }, [](Variant) -> int { return 42; }); 
    } 

    return 0; 
} 

합니다.

그러나 순서가 잘못 선언 되었기 때문에 오류가 발생했을 것으로 예상됩니다. 그 이유는 그것이 아닌 이유는이 함수들이 모두 템플릿 화되어 있다는 사실과 관련이 있다고 가정합니다. 그러나 variantToMap # 1 내의 variantToMap # 4에 대한 호출이 3 개의 인수 (즉,

)를 갖고 있기 때문에 이것이 다소 혼란 스럽습니다. 또는 Clang과 GCC가 이러한 함수를 부적절하게 수용하고 있습니까? 허용되는 경우, 그 이유는 무엇입니까?

나는이 기능들을 이미 재정리했다는 것을 알아야한다. 처음에는 왜 작동했는지 궁금하다.

+0

정확하게 오류가있는 이유와 그 이유를 알려주십시오. 해당 줄에 주석을 넣으십시오. '//이 줄은 독립된 식별자 foobar를 사용하기 때문에 여기에 에러가 올 것이라고 기대한다. –

+0

@ n.m. 요청한 정보를 추가했습니다. – OmnipotentEntity

답변

2

C++은 two phase name lookup을 사용하여 템플릿 정의에있는 식별자를 확인합니다. (MSVC가없는 한 두 번째 단계 만 사용합니다.)

템플릿이 선언/정의되면 템플릿 인수에 의존하지 않는 모든 이름이 해석됩니다. 인스턴스화 될 때 템플릿 인수에 의존하는 이름이 해석됩니다. 이번에는 인스턴스화 시점에 표시되는 이름이 조회 중에 찾아 볼 수 있습니다.

variantToMap 내부 호출은 템플릿 인수에 따라 달라 지므로 외부 함수가 호출 될 때까지 해결되지 않습니다. 이 시점에서 4 가지 변종이 모두 보이고 찾을 수 있습니다.

관련 문제