Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Is this a defect in C++ that std::get<T> ( const std::pair<const T, U>& ) fail to compile due to const T?

Tags:

c++

c++14

As title.

This compile error occurs when using the std::get<T>(pair), where the first member of the pair is a const, coming off an iterator for std::map or std::unordered_map.

To test the compile error, comment out the "notstd" overload of get.

I have researched this question on Stack Overflow with the three most relevant questions listed below.

The existing answers lead me to believe that it should be a defect report, that the respective std::get overload should have been added to the standard library, and that the automatic lifetime extension applied to temporary constant reference should be extended to cover such cases.

I have also researched whether it has to do with specialization of layouts (question 14272141, linked below). However, my code snippet only asks for the const reference to one of the two members; even with specialization of layouts, the const reference to either member should still exist.

I understand that casting between const std::pair<T, U>& and const std::pair<const T, U>& would not be safe, based on the existing answers.

namespace notstd
{
    template <class T, class U>
    const T& get(const std::pair<const T, U>& tu)
    {
        return tu.first;
    }
}
int test(int value) 
{
    using namespace notstd;
    using namespace std;
    const std::pair<const int, bool> one(value, false);
    const auto two = get<int>(one);
    const auto three = get<const int>(one);
    return 0;
}

Questions with high relevance:

  • Bind const std::pair<T, U>& to value of std::pair<const T, U>
  • Is casting std::pair<T1, T2> const& to std::pair<T1 const, T2> const& safe?
  • std::is_assignable and std::pair<const T, U>

(Humility notice: even though I claimed that this seems like a defect report, there may be some missing knowledge in my head, so please do let me know. From rioki's answer below, I can see that the current design allows distinguishing the two arguments in a std::pair<const int, int> whereas my proposal would fail.)

My characterization of the present situation:

  • Annoying inconsistency, because the issue arises when two idioms (typed-get, and consistent use of range-based-for from vector<pair> and unordered_map<pair>) are used together, and the explanation for this incompatibility is not exactly palatable to anyone including beginners and experienced programmers.
  • One or more satisfactory workarounds exist, as explained in rioki's answer.
  • Perhaps not so much of a defect report (because existing code may have depended on the ability to distinguish between a const int from an int.), or that it cannot be improved without breaking existing code.
like image 222
rwong Avatar asked Jan 29 '18 20:01

rwong


1 Answers

Is this a defect in C++ that std::get<T>(const std::pair<const T, U>& ) fail to compile due to const T?

No. I would very much expect this to fail:

std::pair<const int, bool> p(42, true);
std::get<int>(p); // expected failure

std::get<T> means to retrieve the element whose type is T. Not the element whose type approximates T, or decays to T, or any other such. std::get comes to pair by way of tuple, where it is specified as:

Requires: The type T occurs exactly once in Types.... Otherwise, the program is ill-formed.

If we consider pair as a special case of tuple, int does not occur exactly once in {const int, bool}, so the program should be ill-formed.

Put in other words: you are asking for the int in that pair, but there is no int there. There's a const int and there's a bool.

like image 154
Barry Avatar answered Sep 29 '22 18:09

Barry