2011-09-30 2 views
6

나는 호출을위한 다른 일치가 전혀 없을 때만 적용될 수있는 함수 foo의 일반 버전을 제공하고자하는 곳에 문제가 있습니다. last_resort::fooderived::type보다 좋지 않은 코드 인 base::foo을 수정하려면 어떻게해야합니까? bar의 정의를 수정하지 않고 last_resort::foo의 인수 유형을 보존하는 솔루션을 찾고 싶습니다.ADL 동안 함수 템플릿의 우선 순위를 낮추는 방법은 무엇입니까?

#include <iostream> 

namespace last_resort 
{ 

template<typename T> void foo(T) 
{ 
    std::cout << "last_resort::foo" << std::endl; 
} 

} 

template<typename T> void bar(T) 
{ 
    using last_resort::foo; 
    foo(T()); 
} 

namespace unrelated 
{ 

struct type {}; 

} 

namespace base 
{ 

struct type {}; 

void foo(type) 
{ 
    std::cout << "base::foo" << std::endl; 
} 

} 

namespace derived 
{ 

struct type : base::type {}; 

} 

int main() 
{ 
    bar(unrelated::type()); // calls last_resort::foo 
    bar(base::type());  // calls base::foo 
    bar(derived::type()); // should call base::foo, but calls last_resort::foo instead 

    return 0; 
} 

답변

0

last_resort::foodisable_if 설정 과부하로부터 제거 될 수있다. 그 이유는 foo(T)이 잘 구성된 경우 last_resort::foo(T)을 비활성화하는 것입니다.

namespace test 
{ 

template<typename T> struct has_foo { ... }; 

} 

namespace last_resort 
{ 

template<typename T> 
    struct disable_if_has_foo 
    : std::enable_if< 
     !test::has_foo<T>::value 
     > 
{}; 

template<typename T> 
    typename disable_if_has_foo<T>::type foo(T) 
{ 
    std::cout << "last_resort::foo" << std::endl; 
} 

} 

출력 :

$ g++ last_resort.cpp 
$ ./a.out 
last_resort::foo 
base::foo 
base::foo 

This answervoid를 반환하는 함수 (foo)의 존재를 확인하기위한 솔루션을 구축하는 방법에 대해 설명이 foo에 대한 최악의 경기로 last_resort::foo(T)됩니다.

1

많은 작업을 수행 할 수 없습니다. 두 foo 함수는 오버로드 집합에 있습니다. 그러나 last_resort는 더 나은 일치입니다. 왜냐하면 derived :: type()에 대해 base :: foo와는 달리 변환을 요구하지 않기 때문입니다. 두 후보자가 매개 변수와 가능한 전환으로 판단 할 때 "동등하게 우수"한 경우에만 비 템플릿이 선호됩니다.

+0

사실입니다. 그러나 foo에 기본값으로 추가 매개 변수를 추가하여 "숨겨진"변환을 도입 할 수있는 방법이 있는지 궁금합니다. –

+0

작동하지 않을 것이라고 생각합니다. 당신이 얻을 수있는 "최선"이라고 말할 수있는 것은 모호하므로 컴파일이 실패합니다. 하지만 어쩌면 뭔가 빠져있는 것일 수도 있습니다. – sellibitze

+0

해결책은'''last_resort :: foo'''의 리턴 타입을''disable_if_foo_exists :: type''과 같이 꾸미는 것으로 보인다. SFINAE를 사용하여 자유로운''foo '''기능. 만약 존재한다면,''last_resort :: foo'''는 오버로드 세트에서 제거 될 것입니다. –

0

derived::type 선언 후 derived::type 유형에 대해 bar의 과부하를 제공 할 수 있습니다. 이것은 namespace derived 일 수 있습니다.

void bar(derived::type) 
{ 
    foo(derived::type()); 
} 
2

이수록 이것은 나쁜 대해 다음과 같습니다

struct badParam { template <typename T> badParam(T t) { } }; 
namespace last_resort { 
    void foo(badParam, int dummy = 0, ...) { 
    std::cout << "last_resort::foo" << std::endl; 
    } 
} 

당신은 사용자 정의 변환하는 궐석 매개 변수 및 사용되지 않는 생략 부호를 가지고있다.

[편집]

약간 변형, I는 상기 더미 파라미터 사용자 정의 변환 이동 T을 저장 :

struct badParam { 
    badParam() { } 
    operator int() { return 42; } 
}; 
namespace last_resort { 
    template <typename T> void foo(T t, int dummy = badParam(), ...) { 
    std::cout << "last_resort::foo" << std::endl; 
    } 
} 
+0

감사합니다. 나는''''badParam'' 만 추가하면 강등시킬 수 있다고 생각하지만 변환 과정에서''''''의 형식을 지우는 것으로 생각합니다. –

+0

최후의 수단의 경우, 어쨌든 T에 의존 할 수는 없습니다. 왜냐하면 모든 이상한 타입을 얻었 기 때문입니다. 그러나 그것을 저장하는 것은 어렵습니다. 템플릿 인수 공제는 사용자 정의 변환을 생성하지 않습니다. – MSalters

+0

고대 게시물이지만 임의의 생각 : 원래의 badParam을 사용하는 방법은 어떻습니까?하지만 badParam을 호출 할 실제 함수에 대한 템플릿 인수 값 포인터가있는 템플릿 유형으로 만드는 방법은 생성자에서 수행하는 것입니다. – Yakk

관련 문제