2

Hello I have this simple question:

std::pair<int, int*> foo( int* p1, int* p2)
{
    return make_pair<int, int*>(*p1, p2); // error
}

Why can I not supply the element types explicitly to the template function std::make_pair? I know that the template deduces the element types from the arguments but why can I not specify them explicitly?

The thing that matters to me is if I implement my own pair and make_pair it works fine:

template<typename T, typename U>
struct Pair
{
    T first_;
    U second_;
};

template<typename T, typename U>
Pair<T, U> Make_Pair(T x, U y)
{
    return Pair<T, U>{ x, y };
}

Pair<int, int*> foo(int* p1, int* p2)
{
    return Make_Pair<int, int*>(*p1, p2); // works fine
//  return Make_Pair(*p1, p2); // works fine
}
Boann
  • 48,794
  • 16
  • 117
  • 146
Maestro
  • 2,512
  • 9
  • 24
  • 3
    [Pro Tip] Don't manually specify template types. Let the compiler figure it out for you. – NathanOliver Jan 15 '20 at 21:57
  • 1
    [It isn't that simple to do this "by hand"](https://en.cppreference.com/w/cpp/utility/pair/make_pair) – PaulMcKenzie Jan 15 '20 at 21:58
  • 3
    @NathanOliver I think Maestro knows this, but the question here is why can't you manually specify them? I just threw this in Visual Studio and it surprised me as well. – tjwrona1992 Jan 15 '20 at 21:58
  • https://stackoverflow.com/questions/19358240/weird-compiler-error-cannot-convert-parameter-from-int-to-int this should be the correct duplicate? – Sreeraj Chundayil Jan 15 '20 at 22:02
  • @InQusitive I've added it to the list. – NathanOliver Jan 15 '20 at 22:03
  • 2
    Still keeping my upvote because this question is much clearer and to the point than the other duplicates. – tjwrona1992 Jan 15 '20 at 22:07
  • do `return std::pair(*p1, p2);` if that's what you want -- the purpose of `make_pair` is for having the types be deduced – M.M Jan 15 '20 at 22:20
  • @M.M: Let the compiler deduce. `return {*p1, p2};` – Mooing Duck Jan 15 '20 at 22:25
  • 2
    Do note that your `make_pair` is not the same as [`std::make_pair`](https://en.cppreference.com/w/cpp/utility/pair/make_pair) (ignore the pre C++11 version since your not using Pre C++11) – NathanOliver Jan 15 '20 at 22:25
  • @MooingDuck I was covering the situation where they wanted to explicitly specify instead of deducing (figured that if they wanted to deduce they would not have listed the types in the first place) – M.M Jan 15 '20 at 22:29
  • Why marked as "already has an answer"? The answer: you cannot pass an lvalue as an rvalue in this context so you need to pass an rvalue `make_pair` please google it. To make your code works: `std::pair foo(int* p1, int* p2) { return make_pair(int(*p1), (int*)p2); // convert l-values to r-values. should work now }` – Raindrop7 Jan 15 '20 at 22:29
  • @Raindrop7 That's terrrible advice. To make the code work they just need `return make_pair(*p1, p2);` or even better like Mooing Duck commented, `return {*p1, p2};`. Creating unneeded temporaries is bad code. – NathanOliver Jan 15 '20 at 22:37
  • @NathanOliver: But I show the OP why the his code didn't work. – Raindrop7 Jan 15 '20 at 22:50
  • @tjwrona1992: The same problem both on GCC and Clang. The problem is make_pair is defined by the library to take r-values not l-values thus it fails to compile. – Raindrop7 Jan 15 '20 at 22:52
  • @Raindrop7 You really didn't. `make_pair` is designed to take rvalues. It has forwarding references parameters which accepts lvalues and rvalues. It's when you manually specify the template type that you break that mechanic and you are stuck with just accepting rvalues. – NathanOliver Jan 15 '20 at 22:54
  • @NathanOliver: But why said "Don't manually specify template types. Let the compiler figure it out for you. " and didn't the reason in this case? There are many template functions that you can specify element types for them and they work as needed. – Raindrop7 Jan 16 '20 at 18:11

0 Answers0