0

나는 함수에 foo 참조를 매개 변수로 가지고 있고, 나는 rvalue와 lvalue 참조에서 다르게 행동하기를 원합니다. 이 방법 즉, 오히려를 rvalue 참조보다템플릿 추론 형을 사용하여 rvalue 및 lvalue 참조에 대해 서로 다른 오버로드를 얻는 방법은 무엇입니까?

template <typename T> foo(T&& x); 

을 나는 forwarding reference를 선언했습니다 : 내가 작성하는 경우 알고 (그것은이-에 대해 참조 가치, 내가 추가 할 수 있습니다 변경되지 않음)

template <typename T> foo(const T& x); 
template <typename T> foo(T&& x); 

내가 원하는 것을 얻을 수 없을 것입니다.

내 질문은 : 두 가지 종류의 참조 사이의 다른 동작에 영향을주는 올바른 방법은 무엇입니까?

+2

포워딩 참조가 원하는 것과 다르기 때문에 원하는 것을 제공 할 수 있습니까? – Barry

+0

@Barry : rvalue 참조를 위해 힙 공간을 할당하고, lvalue 참조에 아무 것도 할당하지 않습니다. 따라서 어떤 종류의 콜백에서 사용할 수 있습니다. – einpoklum

+0

사용자가 핸들러에 대한 참조를 원할 경우 std :: ref에 전달하도록 요구하는 일반적인 방법이 아닙니까? –

답변

1

C++ 11에는 태그 디스패치를 ​​사용하고 C++ 17에는 if constexpr을 사용할 수 있습니다. 그런 것.

template <typename T> 
void foo(T&& x) 
{ 
    foo(std::addressof(x), typename std::is_lvalue_reference<T>::type{}); 
} 
void foo(void const *value, std::true_type) 
{ 
    // do something on lvalue 
} 
void foo(void const *value, std::false_type) 
{ 
    // do something on rvalue 
} 

포인터를 나중에 reinterpret_cast으로 지정하면 해당 유형에 대한 정보를 저장해야합니다. 이상과 같이 제안 :

lvalues를 들어
template <typename T> void foo(T&) { ... } 
template <typename T> void foo(T&&) { ... } 

, 최초의 과부하가 선호 :

template <typename T> 
void foo(T&& x) 
{ 
    foo(std::forward<T>(x), typename std::is_lvalue_reference<T>::type{}); 
} 
template <typename T> 
void foo(T &&value, std::true_type) 
{ 
    // do something on lvalue 
} 
template <typename T> 
void foo(T &&value, std::false_type) 
{ 
    // do something on rvalue 
} 
+0

이제 유형 정보가없는 두 개의 도우미 함수가 생깁니 까? -1. – Barry

+0

여기서 포인터 나 캐스트를 사용할 필요가 없습니다. –

+0

다른 템플릿을 사용하는 것이 좋습니다. –

7

당신은 좌변 참조 과부하 및 전달 참조 과부하를 할 수 있습니다. r 값의 경우 두 번째 오버로드 만 실행 가능합니다.


당신이 원하는 것은 당신이 바로 전달 참조 경우에 제약 조건을 추가해야 참조 과부하 좌변 하나 const를 하나의 const가 아닌를 rvalue 참조 과부하 인 경우 :

template <typename T> void foo(T const&) { ... } 
template <typename T, REQUIRES(!std::is_reference<T>::value)> 
void foo(T&&) { ... } 

REQUIRES입니다 당신이 선택한 방법. 지금, 우리의 사가지 경우에 대한 :

  • const가 아닌, 좌변이 : 만 1가 가능한
  • CONST의 좌변은 다음과 같습니다에만 1가 가능한
  • const가 아닌,를 rvalue입니다 : 가능한 모두 2는 더 나은 경기를
  • 입니다
  • CONST의를 rvalue : 모두 가능한, 둘째는
+0

나는 이것이 가장 쉬운 가장 쉬운 방법이기 때문에 투표했습니다. 그러나 OP는 그들의 const 정확성을 다시 생각해야 할 것입니다, 그렇지 않으면 이것은 일어날 것입니다 (http://coliru.stacked-crooked.com/a/45b60c6b9915ce3f). – StoryTeller

+0

첫 번째 변형에서 const를 제거했습니다. 그것이 의도적인지, 그렇다면 @ StoryTeller의 의견에 비추어 정교 할 수 있습니까? – einpoklum

+0

@StoryTeller 첫 번째 과부하에는 'const'가 없습니다. – Barry

1

태그 파견 가장 간단한 솔루션으로 더 나은 경기를 보다 전문입니다.

namespace details { 
    template <typename T> 
    void foo(std::true_type is_lvalue, const T& x) { 
    std::cout << x << " is an lvalue\n"; 
    } 
    template <typename T> 
    void foo(std::false_type is_lvalue, T&& x) { 
    std::cout << x << " is an rvalue\n"; 
    } 
} 
template <typename T> 
void foo(T&& t) { 
    return details::foo(
    typename std::is_lvalue_reference<T>::type{}, 
    std::forward<T>(t) 
); 
} 

SFINAE는 과부하 해결을 위해 선택된 버전을 실제로 지원하지 않으려는 경우에 심각한 과잉입니다.

관련 문제