4

Reedited: first of all, this is just a matter of curiosity, I do know, that std::pair or lots of other solutions could eradicate this issue.

Can you tell me, what is exactly behind of this following problem? This code is a simple example working on c++03 and fails on c++11.

    std::pair<int*,int**> getsth(int* param)
    {
        return std::make_pair<int*,int**>(param, 0);
    }

    int main(int argc, char* argv[])
    {
        int* a = new int(1);
        std::pair<int*,int**> par = getsth(a);
        std::cout << *par.first;
        return 0;
    }

I do know how to fix it to be compatible with both standards here, but it is annyoing me, that I don't know, what is exactly behind make_pair in this case.

Thanks!

edited: a compile error message from Coliru:

main.cpp: In function 'std::pair<int*, int**> getsth(int*)':
main.cpp:8:47: error: no matching function for call to 'make_pair(int*&, int)'
     return std::make_pair<int*,int**>(param, 0);
                                               ^
main.cpp:8:47: note: candidate is:
In file included from /usr/local/include/c++/4.9.2/bits/stl_algobase.h:64:0,
                 from /usr/local/include/c++/4.9.2/bits/char_traits.h:39,
                 from /usr/local/include/c++/4.9.2/ios:40,
                 from /usr/local/include/c++/4.9.2/ostream:38,
                 from /usr/local/include/c++/4.9.2/iostream:39,
                 from main.cpp:1:
/usr/local/include/c++/4.9.2/bits/stl_pair.h:276:5: note: template<class _T1, class _T2> constexpr std::pair<typename std::__decay_and_strip<_Tp>::__type, typename std::__decay_and_strip<_T2>::__type> std::make_pair(_T1&&, _T2&&)
     make_pair(_T1&& __x, _T2&& __y)
     ^
/usr/local/include/c++/4.9.2/bits/stl_pair.h:276:5: note:   template argument deduction/substitution failed:
main.cpp:8:47: note:   cannot convert 'param' (type 'int*') to type 'int*&&'
     return std::make_pair<int*,int**>(param, 0);
                                               ^
main.cpp:9:1: warning: control reaches end of non-void function [-Wreturn-type]
 }
newhouse
  • 1,152
  • 1
  • 10
  • 27
  • 2
    Please show your compile error, assuming there is one – Useless Mar 31 '15 at 15:24
  • 2
    Writing `std::make_pair(param, 0)` is [totally pointless](http://www.advogato.org/person/redi/diary/239.html), the whole point of `make_pair` is to deduce the argument types. If you don't want the types to be deduced then just say `std::pair(param, 0)` and save yourself typing five redundant characters. – Jonathan Wakely Mar 31 '15 at 15:43
  • 1
    Just going to point out `return {param, 0};` – chris Mar 31 '15 at 15:47
  • 2
    @chris Not going to work in 03. – T.C. Mar 31 '15 at 15:47

2 Answers2

8

Rvalue references happened. Where std::make_pair in C++03 has the signature

template< class T1, class T2 >
std::pair<T1,T2> make_pair( T1 t, T2 u );

In C++11, it has

template< class T1, class T2 >
std::pair<V1,V2> make_pair( T1&& t, T2&& u );

V1 and V2 are (usually) std::decay<T1|T2>::type. C++14 adds constexpr, but that does concern us here.

This means that the explicit function template specialization std::make_pair<int*, int**> accepted, in C++03, parameters of type int* and int**, while the new one in C++11 accepts int*&& and int**&&.

Binding 0 to int**&& is not a problem, but param is an lvalue and cannot be bound to an rvalue reference to int*. And that is why your code explodes in C++11.

For this reason,

return std::make_pair<int*&, int**>(param, 0);

works with both C++03 and C++11 -- param can be bound to int*&, and the resulting std::pair<int*&, int**> can be converted to the std::pair<int*, int**> that the function wants to return in both revisions.

That is rather ugly, though, and std::make_pair is not really meant to be used this way. As @T.C. points out in the comments, if you know the types the std::pair should have, just use

return std::pair<int*, int**>(param, 0);
Wintermute
  • 42,983
  • 5
  • 77
  • 80
  • 3
    `std::pair(param, 0)`. `make_pair` is never meant to be used with explicit template arguments. – T.C. Mar 31 '15 at 15:42
  • 1
    Thanks, this was somewhat my guess. But doesn't have it a normal definition as well? – newhouse Mar 31 '15 at 15:42
  • 1
    @newhouse I think he meant that the answer should mention this, and I agree -- it will still be here in a year, and it's not just us who're potentially going to read it. – Wintermute Mar 31 '15 at 15:49
  • 2
    @newhouse, why do you think T.C. is being a smartass? Why do you think `return std::pair(param, 0)` is not compatible with the return type? – Jonathan Wakely Mar 31 '15 at 15:49
  • @JonathanWakely I misread that one, yeah, that is ok. – newhouse Mar 31 '15 at 15:52
  • Yet still, this was just a question of curiosity and I just wanted to know, what was the exact problem behind this in c++11, because it worked in c++03. And we got an answer below, so... – newhouse Mar 31 '15 at 15:55
3

You need to remove the template parameters of make_pair. Here is more info on why.

Also, you should pass nullptr to make_pair, not 0.

Community
  • 1
  • 1
dwcanillas
  • 3,562
  • 2
  • 24
  • 33
  • 3
    I think the problem is it also needs to be C++03 compliant, which I don't know if it would be, without explicit parameters. – Giulio Franco Mar 31 '15 at 15:34
  • 1
    You missed the part "C++03 compilant", as well as the fact, that I have an exact return type, so if I remove the template parameter definition of make_pair, it won't compile either. – newhouse Mar 31 '15 at 15:41
  • @newhouse it would, if you didn't use 0 as a pointer. There's no `nullptr` in C++03, but you can still hardtype it `reinterpret_cast(0)`. – Giulio Franco Mar 31 '15 at 15:45
  • 2
    @GiulioFranco `s/reinterpret/static/`. – T.C. Mar 31 '15 at 15:48
  • @T.C. does it have any importance when dealing with nulls? – Giulio Franco Mar 31 '15 at 15:49
  • 2
    @GiulioFranco `static_cast` is guaranteed to work. `reinterpret_cast` isn't. – T.C. Mar 31 '15 at 15:50
  • @GiulioFranco Yeah, that one was out of scope, because the original code, where I got this had some other make_pairs with NULLs and this would have been a misery. I used &*param at make_pair to create and rvalue :) – newhouse Mar 31 '15 at 15:51