3

When using std::sort, how can I overload the custom comparison function that I am using?

#include <string>
#include <vector>
#include <iostream>
#include <algorithm>

class Misc {
public:
  // Comment out the next three lines to compile without problems.
  static bool sortPair(const std::pair<int, int> &a, const std::pair<int, int> &b){
    return a.first < b.first;
  }
  static bool sortPair(const std::pair<double, std::string> &a, const std::pair<double, std::string> &b){
    return a.first < b.first;
  }
};

int main () {
  std::vector<std::pair<double, std::string> > u;
  u.push_back(std::make_pair(10.0, "ten"));
  u.push_back(std::make_pair(5.0, "five"));
  u.push_back(std::make_pair(1.0, "one"));

  std::sort(u.begin(), u.end(), Misc::sortPair);

  for (unsigned int i=0; i< u.size(); i++){
    std::cout << u.at(i).first << std::endl;
  }

  return 0;
}

I can't get this to compile as it complains about:

unresolved overloaded function type

I can see that using sortPair could be somewhat ambiguous, but I assumed that the compiler would be able to resolve this based on the types associated with the vector u. Is there some way that I could specify which function/method to use in order to disambiguate the problem?

Currently, commenting out the first sortPair function allows the code to be compiled and produces the correct sorted output. Of course, this is because it is not longer ambiguous.

8
  • 1
    Why isn't the second argument to your compare functions also a const reference? It's missing the &. Commented Nov 18, 2013 at 4:14
  • To manully resolve the overload, use static_cast. Commented Nov 18, 2013 at 4:23
  • I've edited my question. Thanks. How do I use "static_cast" in this instance? Commented Nov 18, 2013 at 5:21
  • possible duplicate of unresolved overloaded function type c++ Commented Nov 18, 2013 at 8:25
  • You have to manually cast it to the correct function pointer type to help the compiler disambiguate the call. Commented Nov 18, 2013 at 8:27

3 Answers 3

4

You can use a functor instead:

class Misc {
  public:
    // static bool sortPair(const std::pair<int, int> &a, const std::pair<int, int> &b);
    // static bool sortPair(const std::pair<double, std::string> &a, const std::pair<double, std::string> &b);
    bool operator() (const std::pair<int, int> &a, const std::pair<int, int> &b) { // something 
        return true;
    }
    bool operator() (const std::pair<double, std::string> &a, const std::pair<double, std::string> &b) { // something 
        return true;
    }
} misc;

int main()
{
    std::vector<std::pair<double, std::string> > u;
    std::vector<std::pair<int, int> > u2;
    //Fill vector u with data
    std::sort(u.begin(), u.end(), misc);
    std::sort(u2.begin(), u2.end(), misc);
    return 0;
}
Sign up to request clarification or add additional context in comments.

3 Comments

I never thought about your answer so thank you. However, I am looking for a way to change the sort line in main so that my original class remains unchanged. The emphasis of my question is really on the disambiguation rather than a complete alternative.
@slaw As I pointed out in my edit, you can pass it by reference without changing any other code.
Passing it by reference didn't compile and wasn't necessary. Instead, simply commenting out the first sortPair function compiled and sorted the vector accordingly (i.e. it removed the ambiguity). Although, it still isn't clear how I could get the code to recognize which function to use without commenting the first sortPair.
1

Since u is a vector of std::pair<double, std::string>, you will want to have the corresponding comparison function called. Since the name alone is not sufficient, you will have to disambiguate it for the compiler by casting it to a pointer with the right function pointer type. In your case it is a function that takes two const references to the pair type and returns a bool - so the function pointer type you have to cast to is exactly that:

bool (*)(const std::pair<int, int> &, const std::pair<int, int> &)

Together that makes a pretty ugly cast:

std::sort(u.begin(), u.end(), static_cast<bool (*)(const std::pair<int, int> &, const std::pair<int, int> &)>(&Misc::sortPair));

Whoa.

Better use some typedefs to clarify what you are doing:

//includes as they were...
typedef std::pair<double, std::string> dsPair; //or something more meaningful

class Misc {
public:
  //Comment out the next three lines to compile without problems
  static bool sortPair(const std::pair<int, int> &a, const std::pair<int, int> &b){
    return a.first < b.first;
  }
  static bool sortPair(dsPair const& a, dsPair const& b){
    return a.first < b.first;
  }
};

int main () {
  std::vector<dsPair> u{ 
    {10.0, "ten"},
    {5.0, "five"},
    {1.0, "one"}
  };

  /** the function pointer typedef
   * It takes a bit getting used to, but no worries, 
   * you won't have to do it THAT often:
   **/
  typedef bool(*dsPairCompFunc)(dsPair const&, dsPair const&); 

  //and now the cast is much clearer:
  std::sort(begin(u), end(u), static_cast<dsPairCompFunc>(&Misc::sortPair));

  for (auto& e : u){
    std::cout << e.first << "\n";
  }

  return 0;
}

I changed some of the old C++03 stuff to C++11 in case your compiler supports it.

2 Comments

Is the ampersand necessary in (&Misc::sortPair)? I've typically left this out and this is the first time I've seen it used in the sort comparison function.
@slaw no it's not necessary, the function reference will implicitly be converted to a function pointer. I just like to make it explicit that a function pointer is taken.
0

Since C++11, you can also use lambda expressions instead of defining comparison functions. This way, you neither need your Misc class nor worry about function disambiguation:

int main() {
  using dbl_str_pair_t = std::pair<double, std::string>;
  std::vector<dbl_str_pair_t> u {{10.0, "ten"}, {5.0, "five"}, {1.0, "one"}};

  using int_int_pair_t = std::pair<int, int>;
  std::vector<int_int_pair_t> v {{3, 4}, {1, 5}, {2, 6}};

  std::sort(std::begin(u), std::end(u), [](const dbl_str_pair_t& a, const dbl_str_pair_t& b) {
    return a.first < b.first;
  });

  std::sort(std::begin(v), std::end(v), [](const int_int_pair_t& a, const int_int_pair_t& b) {
    return a.first < b.first;
  });

  for (auto const &p : u)
    std::cout << p.first << std::endl;

  for (auto const &p : v)
    std::cout << p.first << std::endl;

  return 0;
}

Code on Ideone

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.