Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

std::map non-const functors, compile time error under clang++, ok for g++

I am curious if anyone knows why g++ compiles the code below but clang++ gives an error. The code creates a std::map<int, int, SortCriterion> with a custom sort functor SortCriterion. One can specify via the constructor of SortCriterion the type of sorting: ascending or descending. The key comparison is implemented via operator()(int, int). Everything compiles and runs OK under g++, even with -Wall, -Wextra, Wpedantic etc. However, clang++ spits an error when invoking the insert function, and complains about const-ness for the comparison operator, i.e. wants operator()(int, int) const.

note: candidate function not viable: 'this' argument has type
      'const SortCriterion', but method is not marked const
    bool operator()(int x, int y) //const

Now I know that keys in associative containers should not to be messed with, since will damage the internal structure of the container, but is const-ness enforced by STL? It seems that the clang++ expects std::map<key, value, const comparator>, whereas g++ does not impose const.

PS: g++4.9, Apple LLVM version 5.1 (clang-503.0.40)

#include <map>
#include <string>
#include <iostream>

using namespace std;

class SortCriterion
{
    bool ascending;
public:
    SortCriterion(bool sorting_type): ascending(sorting_type){};
    // if operator below is not marked const, 
    // clang++ spits a compile-time error on insert
    // however g++ compiles it ok
    bool operator()(int x, int y) //const
    {
        if(ascending) // ascending
            return x<y;
        else
            return x>y;
    }
};

int main()
{
    map<int, string, SortCriterion> m(SortCriterion(false)); // ascending

    m.insert({1,"one element"}); // clang++ compile error here
    m.insert({2,"another element"});
    for(auto elem: m)
        cout << elem.first << ": " << elem.second << endl;
}
like image 943
vsoftco Avatar asked Oct 01 '22 05:10

vsoftco


1 Answers

The C++11 Standard documents a member of std::map:

class value_compare {
    friend class map;
protected:
    Compare comp;
    value_compare(Compare c) : comp(c) {}
public:
    typedef bool result_type;
    typedef value_type first_argument_type;
    typedef value_type second_argument_type;
    bool operator()(const value_type& x, const value_type& y) const {
        return comp(x.first, y.first);
    }
};

...given value_compare::operator() is const, it can't call a non-const member on comp. That means Compare absolutely must have a const operator() for this part of the API to be usable.

like image 132
Tony Delroy Avatar answered Oct 13 '22 17:10

Tony Delroy