0

Currently using C++20, GCC 11.1.0

I'm trying to create a class method that returns a std::pair of uint32_t and a reference to a unique pointer. The unique pointer comes from a vector of unique pointers stored as a variable in the class. However, it keeps saying:

error: could not convert ‘std::make_pair(_T1&&, _T2&&) [with _T1 = unsigned int; _T2 = std::unique_ptr<Panel>&; typename std::__strip_reference_wrapper<typename std::decay<_Tp2>::type>::__type = std::unique_ptr<Panel>; typename std::decay<_Tp2>::type = std::decay<std::unique_ptr<Panel>&>::type; typename std::__strip_reference_wrapper<typename std::decay<_Tp>::type>::__type = unsigned int; typename std::decay<_Tp>::type = unsigned int]((* &((Screen*)this)->Screen::panels.std::vector<std::unique_ptr<Panel> >::emplace_back<>()))’ from ‘pair<[...],std::unique_ptr<Panel>>’ to ‘pair<[...],std::unique_ptr<Panel>&>’
   67 |         return std::make_pair<PanelID, Panel_Ptr&>(
      |                ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~^
      |                                                   |
      |                                                   pair<[...],std::unique_ptr<Panel>>
   68 |             std::move(panelID), panels.emplace_back());
      |             ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
class Screen
{
private:
    using PanelID = uint32_t;
    using Panel_Ptr = std::unique_ptr<Panel>;
    std::vector<Panel_Ptr> panels {};

public:
    std::pair<PanelID, Panel_Ptr&> foo()
    {
        PanelID panelID {static_cast<PanelID>(panels.size())};
        return std::make_pair<PanelID, Panel_Ptr&>(
            std::move(panelID), panels.emplace_back());
    }
};
spaL
  • 604
  • 7
  • 21
  • Possibly related: [make_pair with specified template parameters doesn't compile](https://stackoverflow.com/questions/9641960/) Does it work if you get rid of the explicit template parameters on `make_pair()` (and also get rid of the unnecessary `std::move()`)? `return std::make_pair(panelID, panels.emplace_back());` – Remy Lebeau Aug 27 '22 at 03:06
  • No, it still gives the same error – spaL Aug 27 '22 at 03:10

1 Answers1

2

std::make_pair() will automatically decay any references given to it to their value types.

The deduced types V1 and V2 are std::decay<T1>::type and std::decay<T2>::type (the usual type transformations applied to arguments of functions passed by value) unless application of std::decay results in std::reference_wrapper<X> for some type X, in which case the deduced type is X&.

https://en.cppreference.com/w/cpp/utility/pair/make_pair

Remove your explicit instantiation of the type parameters of std::make_pair() and wrap the emplace_back() call with std::ref:

return std::make_pair(
    std::move(panelID), 
    std::ref(panels.emplace_back())
);

Alternatively, you can explicitly make the std::pair:

return std::pair<PanelID, Panel_Ptr&>(
    std::move(panelID), 
    panels.emplace_back()
);

Finally, to note on your code, you are calling std::move() on your PanelID type even though it is just an integer. std::move() is useless in that scenario, so removing it entirely would make your code clearer.

Though, putting the generation of panelID on a separate statement is still necessary due to the unspecified order of evaluation of arguments passed to functions. Good awareness of this fact.

DXPower
  • 391
  • 1
  • 11
  • 1
    "*putting it on a separate line is still necessary due to the unspecified order of evaluation of arguments passed to functions*" - the compiler ignores whitespace between statements, arguments, etc, so putting the arguments on separate lines makes no difference whatsoever to the compiler, it only enhances readability for humans. – Remy Lebeau Aug 27 '22 at 16:55
  • 1
    @RemyLebeau I believe you misread what I stated there. By line I meant a statement, and they had separated their two statements by line so I said it by line. I will alter the wording to make it more clear. But my point still stands, inside a function call like `foo(a(), b(), c())`, the order that each argument is evaluated is unspecified (ie., a, b, or c can be called in any order). https://en.cppreference.com/w/cpp/language/eval_order "Order of evaluation of any part of any expression, including *order of evaluation of function arguments is unspecified*" – DXPower Aug 29 '22 at 00:31