C++ - rvalue 참조를 사용한 함수 템플릿 특수화 동작
-
12-11-2019 - |
문제
조건부 포인터 역참조 기능을 구현하려고 합니다.기본 아이디어는 다음과 같습니다.
return is_pointer(arg) ? *arg : arg
필요한 전문화의 수를 제한하기 위해 다음과 같은 경우에 rvalue 참조를 사용하려고 합니다. arg
포인터가 아닙니다.현재 구현은 다음과 같습니다( std::cout
디버깅 목적으로만 존재합니다):
template< typename T >
inline typename std::enable_if< std::is_pointer< T >::value == false, T >::type deref(T&& t)
{
std::cout << std::is_pointer< T >::value << std::endl;
std::cout << typeid (T).name() << std::endl;
return t;
}
template< typename T >
inline typename std::enable_if< std::is_pointer< T >::value == true, typename std::remove_pointer< T >::type& >::type deref(T t)
{
std::cout << std::is_pointer< T >::value << std::endl;
std::cout << typeid (T).name() << std::endl;
return *t;
}
이제 GCC 4.6에서는 다소 이상한 동작이 발생합니다.첫 번째 오버로드는 포인터가 아닌 형식과 포인터 형식 모두에 사용됩니다.분명히 포인터 유형을 사용하면 두 번째 오버로드와 충돌합니다.두 번째 것을 주석 처리하고 첫 번째 것을 사용하여 다음을 호출하면...
int q;
int *p = &q;
deref(p);
...해당 콘솔 출력은 다음과 같습니다.
0
Pi
포인터가 아닌 유형이 어떻게 가능합니까? std::is_pointer
)도 포인터 유형입니다(다음에 따르면). typeid
) 같은 맥락에서요?두 과부하 사이에 충돌이 발생합니다. std::is_pointer
잘못 보고하다 p
포인터가 아닌 유형으로.또한 첫 번째 오버로드에서 r-값 참조를 표준 참조로 바꾸면 다음과 같습니다.
inline typename std::enable_if< std::is_pointer< T >::value == false, T >::type deref(T& t)
더 이상 두 번째 과부하와 충돌하지 않습니다.나는 무슨 일이 일어나고 있는지 이해하지 못합니다.그런데 두 번째 오버로드를 사용하면 예상대로 다음과 같은 결과가 나옵니다.
1
Pi
당신의 도움을 주셔서 감사합니다.
해결책
내가 이해하는 한도에서는
template <T>
void foo(T&&)
즉, 만약 T
lvalue이면 참조로 추론됩니다(T = int*&
귀하의 경우) 및 참조 축소 후 int*&&&
일반 lvalue 참조를 생성합니다. int*&
.그렇지 않은 경우 이 구문은 모든 것을 rvalue 참조로 캡처합니다.요점은 lvalue를 lvalue 참조에 바인딩하고 rvalue를 rvalue 참조에 바인딩하는 것입니다.
그리고 is_pointer<int*&>
사실이 아닙니다.따라서 신청해 볼 수도 있습니다. remove_reference<T>
.
다른 팁
첫 번째 과부하 T는 int * &를 추론하고 있습니다.enable_if 테스트 및 출력에서 remove_reference<T>::type
를 사용하려면 첫 번째 과부하를 사용해보십시오.