std :: make_pair와 std :: pair의 생성자의 목적은 무엇입니까?


180

의 목적은 std::make_pair무엇입니까?

왜 안 해 std::pair<int, char>(0, 'a')?

두 방법 사이에 차이점이 있습니까?


6
C ++ 11에서는 make_pair없이 거의 모든 작업을 수행 할 수 있습니다. 내 답변을 참조하십시오 .
PlagueHammer

2
C ++ 17에서는 std::make_pair중복입니다. 아래에 이것을 자세히 설명하는 답변이 있습니다.
Drew Dormann

답변:


165

차이점은 std::pair두 요소의 유형을 지정 해야하는 반면, std::make_pair전달 할 요소의 유형과 쌍을 만들지 않아도 말할 필요가 없다는 것입니다. 어쨌든 다양한 문서에서 수집 할 수있는 것입니다.

http://www.cplusplus.com/reference/std/utility/make_pair/ 에서이 예를 참조하십시오.

pair <int,int> one;
pair <int,int> two;

one = make_pair (10,20);
two = make_pair (10.5,'A'); // ok: implicit conversion from pair<double,char>

make_pair를 사용하지 않은 경우 암시 적 전환 보너스와는 별도로

one = pair<int,int>(10,20)

당신이 하나를 할당 할 때마다, 그것은 시간이 지남에 성가신 것입니다 ...


1
실제로, 유형은 지정하지 않아도 컴파일 타임에 추론되어야합니다.
차드

@Tor Yeah, 둘 다 사용하는 방법을 알고 있습니다 std::make_pair. 이유가 있으면 궁금합니다 . 분명히 그것은 단지 편의를위한 것입니다.

@Jay 그렇게 보일 것입니다.
Tor Valamo 2012

15
one = {10, 20}요즘에는 할 수 있다고 생각 하지만 확인하기에 편리한 C ++ 11 컴파일러는 없습니다.
MSalters

6
또한 make_pair구조체, 공용체, 람다 및 기타 doodad를 포함하여 명명되지 않은 유형에서 작동합니다.
Mooing Duck

35

@MSalters가 위에서 대답했듯이 이제 중괄호를 사용하여 C ++ 11 에서이 작업을 수행 할 수 있습니다 (C ++ 11 컴파일러로 이것을 확인했습니다).

pair<int, int> p = {1, 2};

28

C ++ 17 이전에 생성자에서 클래스 템플리트 인수를 유추 할 수 없습니다.

C ++ 17 이전에는 다음과 같은 것을 작성할 수 없었습니다.

std::pair p(1, 'a');

생성자 인수에서 템플릿 유형을 유추하기 때문입니다.

C ++ 17은 그 구문을 가능하게하고 따라서 make_pair중복됩니다.

C ++ 17 이전에는 std::make_pair덜 자세한 코드를 작성할 수있었습니다.

MyLongClassName1 o1;
MyLongClassName2 o2;
auto p = std::make_pair(o1, o2);

더 장황한 대신 :

std::pair<MyLongClassName1,MyLongClassName2> p{o1, o2};

유형을 반복하며 매우 길 수 있습니다.

make_pair생성자가 아니기 때문에 C ++ 17 이전의 사례에서 형식 유추가 작동합니다 .

make_pair 본질적으로 다음과 같습니다.

template<class T1, class T2>
std::pair<T1, T2> my_make_pair(T1 t1, T2 t2) {
    return std::pair<T1, T2>(t1, t2);
}

같은 개념이 insertervs에 적용됩니다 insert_iterator.

또한보십시오:

최소 예

보다 구체적으로하기 위해 다음을 사용하여 문제를 최소한으로 관찰 할 수 있습니다.

main.cpp

template <class MyType>
struct MyClass {
    MyType i;
    MyClass(MyType i) : i(i) {}
};

template<class MyType>
MyClass<MyType> make_my_class(MyType i) {
    return MyClass<MyType>(i);
}

int main() {
    MyClass<int> my_class(1);
}

그때:

g++-8 -Wall -Wextra -Wpedantic -std=c++17 main.cpp

행복하게 컴파일하지만 :

g++-8 -Wall -Wextra -Wpedantic -std=c++14 main.cpp

실패 :

main.cpp: In function int main()’:
main.cpp:13:13: error: missing template arguments before my_class
     MyClass my_class(1);
             ^~~~~~~~

대신 작동해야합니다.

MyClass<int> my_class(1);

또는 도우미 :

auto my_class = make_my_class(1);

생성자 대신 일반 함수를 사용합니다.

`std :: reference_wrapper의 차이점

이 의견 은 생성자가 그렇지 않은 동안 std::make_pair언 랩핑 std::reference_wrapper을 언급 하므로 한 가지 차이점이 있습니다. TODO 예.

GCC 8.1.0, Ubuntu 16.04로 테스트되었습니다 .


1
"C ++ 17은이 구문을 가능하게하여 make_pair를 중복시킵니다." std::make_pair-C ++ 17에서 더 이상 사용되지 않는 이유는 무엇 입니까?
andreee

@andreee 확실하지 않습니다. 가능한 이유는 문제가 발생하지 않으므로 이전 코드를 중단 할 필요가 없다는 것입니다. 그러나 나는 C ++위원회의 이론적 근거에 익숙하지 않아 뭔가를 찾으면 핑을합니다.
Ciro Santilli 郝海东 冠状 病 六四 事件 法轮功

1
내가 만난 한 가지 유용한 점은 std :: make_pair <T1, T2> (o1, o2)로 유형을 지정할 수 있다는 것이 암시 적으로 불가능한 유형 o1 또는 o2를 실수로 전달하지 못하게한다는 것입니다. T1 또는 T2로 캐스트 예를 들어, 부호없는 int에 음수를 전달하십시오. -Wsign-conversion -W ++는 c ++ 11의 std :: pair 생성자로이 오류를 포착하지 않지만 std :: make_pair를 사용하면 오류를 포착합니다.
conchoecia

make_pair참조 랩퍼의 랩을 해제하므로 실제로 CTAD와 다릅니다.
LF

26

지정된 형식 인수로 생성자를 사용 make_pair하고 명시 적으로 호출하는 것에는 차이가 없습니다 pair. std::make_pair템플릿 메소드는 주어진 매개 변수를 기반으로 유형을 공제하므로 유형이 상세 할 때 더 편리합니다. 예를 들어

std::vector< std::pair< std::vector<int>, std::vector<int> > > vecOfPair;
std::vector<int> emptyV;

// shorter
vecOfPair.push_back(std::make_pair(emptyV, emptyV));

 // longer
vecOfPair.push_back(std::pair< std::vector<int>, std::vector<int> >(emptyV, emptyV));

21

이것이 C ++ 템플릿 프로그래밍의 일반적인 관용구라는 점은 주목할 가치가 있습니다. Object Generator 관용구로 알려져 있으며 여기에서 자세한 정보와 좋은 예를 찾을 수 있습니다 .

편집 누군가가 의견에서 제안한 것처럼 (제거 된 이후) 다음은 링크가 끊어 질 때 약간 수정 된 링크입니다.

객체 생성기는 유형을 명시 적으로 지정하지 않고도 객체를 생성 할 수 있습니다. 클래스 템플릿에는없는 함수 템플릿의 유용한 속성을 기반으로합니다. 함수 템플릿의 유형 매개 변수는 실제 매개 변수에서 자동으로 추론됩니다. 함수 의 실제 매개 변수에 따라 템플리트 std::make_pair의 인스턴스를 리턴하는 간단한 예제입니다 .std::pairstd::make_pair

template <class T, class U>
std::pair <T, U> 
make_pair(T t, U u)
{
  return std::pair <T, U> (t,u);
}

2
@duck &&C ++ 11 이후 실제로 .
Justme0

5

make_pair는 직접 생성자 위에 추가 복사본을 만듭니다. 나는 항상 간단한 구문을 제공하기 위해 쌍을 typedef합니다.
이것은 차이를 보여줍니다 (Rampal Chaudhary의 예).

class Sample
{
    static int _noOfObjects;

    int _objectNo;
public:
    Sample() :
        _objectNo( _noOfObjects++ )
    {
        std::cout<<"Inside default constructor of object "<<_objectNo<<std::endl;
    }

    Sample( const Sample& sample) :
    _objectNo( _noOfObjects++ )
    {
        std::cout<<"Inside copy constructor of object "<<_objectNo<<std::endl;
    }

    ~Sample()
    {
        std::cout<<"Destroying object "<<_objectNo<<std::endl;
    }
};
int Sample::_noOfObjects = 0;


int main(int argc, char* argv[])
{
    Sample sample;
    std::map<int,Sample> map;

    map.insert( std::make_pair( 1, sample) );
    //map.insert( std::pair<int,Sample>( 1, sample) );
    return 0;
}

4
컴파일러의 최적화 설정이 충분히 높으면 여분의 사본이 모든 경우에 제거 될 것이라고 확신합니다.
Björn Pollex 1

1
왜 정확성을 위해 컴파일러 최적화에 의존하고 싶습니까?
sjbx

두 버전 모두에서 동일한 결과를 얻었으며 std::move내부 insert및 / 또는 관련 내용이 있습니다 sample. 내가 변경할 경우에만입니다 std::map<int,Sample>std::map<int,Sample const&>내가 구성 객체의 수를 줄일 것을, 오직 내가 모든 사본을 (분명히) 제거하는 복사 생성자를 삭제할 때. 두 가지 변경을 모두 한 후에는 기본 생성자에 대한 하나의 호출과 동일한 객체에 대한 소멸자에 대한 두 개의 호출이 포함됩니다. 뭔가 빠진 것 같아요. (g ++ 5.4.1, c ++ 11)
John P

FWIW 저는 최적화와 정확성이 완전히 독립적이어야한다는 데 동의합니다. 이는 최적화 수준이 서로 다른 결과가 일치하지 않는 경우 완전성 검사로 작성하는 코드와 정확히 일치하기 때문입니다. 일반적으로 즉시 삽입 할 값을 구성하는 emplace대신 insert(추가 인스턴스를 원하지 않는 경우) 대신 권장 할 것입니다 . 전문가가 있다고 말할 수 있다면 내 전문 분야는 아니지만 복사 / 이동 C ++ 11에서 소개 한 시맨틱은 많은 도움이되었습니다.
John P

나는 똑같은 문제가 발생한다고 생각하고 저녁 내내 디버깅을 마친 후 마침내 여기에 왔습니다.
lllllllllllll

1

c ++ 11부터는 쌍에 대해 균일 한 초기화를 사용하십시오. 따라서 대신 :

std::make_pair(1, 2);

또는

std::pair<int, int>(1, 2);

그냥 사용

{1, 2};

{1, 2}쌍을 초기화하는 데 사용할 수 있지만 유형 쌍을 커밋하지는 않습니다. 즉, auto를 사용할 때 RHS의 유형을 커밋해야합니다 auto p = std::pair{"Tokyo"s, 9.00};.
Markus
당사 사이트를 사용함과 동시에 당사의 쿠키 정책개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.