2016-09-28 5 views
3

tie pre C++ 11의 동작을 모방하려고합니다.make_pair를 사용하여 넥타이 할 수없는 이유는 무엇입니까?

pair<int, int> test() { 
    return make_pair(13, 42); 
} 

int main() { 
    int a = 1, b = 2; 

    pair<int&, int&>(a, b) = test(); 

    cout << a << ' ' << b << endl; 
} 

This works 그러나 나는 대신 pair 생성자 ab가 할당되지 않은에 make_pair를 사용하는 경우.
pair 생성자가 작동하지만 make_pair이 아닌 이유는 무엇입니까?

답변

3

[lib.pairs] 8 pair는 "명시 적 유형"make_pair의 동안 "형식을 사용하는 표준 상태 추론된다 ". 당신이 C++03 compiler에서 코드를 실행하면

template <class T1, class T2> 
pair(const T1& x, const T2& y) 

가이 오류가 발생합니다 : : 표준이 pair에 대한 생성자를 정의하는 이유

이다

non-static reference member int& std::pair<int&, int&>::first , can't use default assignment operator

문제는 pair은을 사용한다는 것입니다 implicitly-declared copy assignment operator은 다음 경우에 정의되지 않습니다. pair :

Has a non-static data member of a reference type

make_pair 또는 pair 생성자로 정의되는지 여부에 관계없이 템플릿 인수는 pair의 구성원을 모두 int&으로 정의하므로 암시 적으로 선언 된 복사본 할당 연산자가 정의되지 않습니다. C++ 03에서는 pair으로이 작업을 수행 할 수 없습니다.tie의 사용 반환 매개 변수가 바람직하지 않은 경우

, 당신이 쓸 수있는 자신의 구현 : 이것은 pair의 할당 수

template <class T1, class T2> 
struct tie{ 
    T1& first; 
    T2& second; 

    tie(T1& x, T2& y) : first(x), second(y) {} 

    tie<T1, T2>& operator=(const pair<T1, T2>& rhs){ 
     first = rhs.first; 
     second = rhs.second; 

     return *this; 
    } 
}; 

:

tie<int, int>(a, b) = test(); 

정확한 C를 얻으려면를 ++ 템플릿 인자를 필요로하지 않는 함수는 함수를 정의해야합니다. 이 단지 C++ 11로 pair의 할당을 허용

template <class T1, class T2> 
details::tie<T1, T2> tie(T1& x, T2& y) { 
    return details::tie<T1, T2>(x, y); 
} 

: tienamespace details에 중첩되어있는 경우 함수는 다음과 같이 정의 할 수 있습니다

tie(a, b) = test(); 

Live Example

참고 여전히 int& 템플릿 인수를 사용하는 것을 용납하지 않으므로 details::tie<int&, int&>tie<int&, int&>은 이전과 마찬가지로 실패합니다.

2

make_pair은 참조가 아닌 한 쌍의 값을 생성합니다. 즉, 예에서 pair<int, int>을 생성하고 test()의 결과를 임시 변수 ¹에 할당 할 수 있습니다.

다음과 tie을 모방 할 수

template<typename T, typename U> 
std::pair<T&, U&> tie_pair(T& l, U& r) 
{ 
    return std::pair<T&, U&>(l, r); 
} 

http://ideone.com/muAcaG

이는 C++ 03 REF-규정을 가지고 있지의 불행한 부작용입니다 ¹. C++ 11 이상에서는 this (평형이 아닌 클래스)에 대해 operator=을 삭제할 수 있으며 이러한 경우에는 자동 동작이 아닌 컴파일러 오류가 발생할 수 있습니다.

+0

나는 이것을하기 위해 당신이 말한 것을 검증했습니다. ' foo = make_pair (a, b)'오류가 있습니다 : "std :: pair '에서 비 스칼라 타입'std :: pair '로의 변환 요청"그래서 분명히 맞지만 이것이 왜 더 복잡한 지 자세히 설명해 주시겠습니까? 'make_pair'가 레퍼런스 타입을 그냥 떼어 내고 있다면 왜 템플릿 인자로 전달할 수 있습니까? –

+1

'make_pair'에 템플릿 매개 변수를 제공하지 않아도됩니다. 당신이 할 수있는 것은 (이 경우 불행한) 언어 의미론의 효과에 불과합니다. * 왜 * 가는가? 그것은 참조가 아닌 독립형 값을 만들기 위해 설계 되었기 때문입니다. 특정 구현에 대해 잘 모르겠습니다. C++ 2003 표준을 사용하면 더 좋은 설명을 줄 수 없습니다. – krzaq

3

실제로는 std::make_pair을 사용할 수 있습니다. 그러나 참조를 모방하기 위해 reference_wrapper 클래스를 구현해야합니다. (예상대로 매우 광택이 아니지만, 작업) 예시적인 C++ 03 방법 : 20.2.2에서

#include <iostream> 
#include <utility> 

using namespace std; 

template <class T> 
struct reference_wrapper { 
    bool is_const; 
    T* v; 
    T const* cv; 
    reference_wrapper(T& t): v(&t), is_const(false) { } 
    reference_wrapper(T const& t): cv(&t), is_const(true) { } 

    reference_wrapper &operator=(reference_wrapper const &rw) { 
     if (rw.is_const) { 
     *v = *rw.cv; 
     } else { 
     *v = *rw.v; 
     } 
    } 
}; 

template <class T> 
reference_wrapper<T> ref(T &t) { 
    return reference_wrapper<T>(t); 
} 

pair<int, int> test() { 
    return make_pair(13, 42); 
} 

int main() { 
    int a = 1, b = 2; 

    //pair<int&, int&>(a, b) = test(); // works 
    make_pair(ref(a), ref(b)) = test(); // now it does work 

    std::cout << a << ' ' << b << std::endl; 
} 
+0

@krzaq not really :) 감사합니다. 편집 ... –

+3

나는이 답변을 내 것보다 더 좋아하지만,'std :: ref'는 C++ 11 이후에만 사용 가능합니다. – krzaq

+1

@krzaq 저는 그것을 말할 것입니다! 'ref'를 사용한다면'tie'를 사용하는 것이 더 낫습니다. –