Johannes Stricker
Johannes Stricker

Reputation: 1781

std::find with two different types

I am trying to use std::find with two different types but providing the necessary boolean operators.

class FooDetails
{
public:
    FooDetails(int size = 5)
    : m_size(size) { /* empty */ }
    bool operator<(const FooDetails& other) const { return m_size < other.m_size; }
    bool operator==(const FooDetails& other) const { return m_size == other.m_size; }
private:
    int m_size;
};

class Foo
{
public:
    Foo(int size)
    : m_details(size) { /* empty */}

    bool operator==(const Foo& other) const { return m_details == other.m_details; }
    bool operator==(const FooDetails& other) const {return m_details == other; }
    bool operator<(const Foo& other) const { return m_details < other.m_details; }
    bool operator<(const FooDetails& other) const { return m_details < other; }
    FooDetails m_details;
};

bool operator==(const FooDetails& lhs, const Foo& rhs) { return lhs == rhs.m_details; }
bool operator==(const Foo& lhs, const FooDetails& rhs) {return lhs.m_details == rhs; }
bool operator<(const FooDetails& lhs, const Foo& rhs) { return lhs < rhs.m_details; }
bool operator<(const Foo& lhs, const FooDetails& rhs) { return lhs.m_details < rhs; }

int main() {
    std::vector<Foo> haystack = { FooDetails(5), FooDetails(6), FooDetails(7) };

    FooDetails needle(6);
    std::find(haystack.begin(), haystack.end(), needle);
    return 0;
}

Since std::find uses operator== I would expect this to work, since all necessary functions are provided. However this does not compile. Why is that and how do I fix it? I know I could use std::find_if, but I assume that's a bit slower and even if it's not I'd like to know why std::find doesn't work.

Upvotes: 0

Views: 377

Answers (2)

Akira
Akira

Reputation: 4473

You have no such constructor in Foo class which constructs it from FooDetails. You need to define the following and your code will work:

Foo(const FooDetails& d) : m_details(d) {}

Upvotes: 1

Dmitry Gordon
Dmitry Gordon

Reputation: 2324

I've changed your code to this:

#include <algorithm>

class FooDetails
{
public:
    FooDetails(int size = 5)
    : m_size(size) { /* empty */ }
    bool operator<(const FooDetails& other) const { return m_size < other.m_size; }
    bool operator==(const FooDetails& other) const { return m_size == other.m_size; }
private:
    int m_size;
};

class Foo
{
public:
    Foo(int size)
    : m_details(size) { /* empty */}

    FooDetails m_details;
};

bool operator==(const FooDetails& lhs, const Foo& rhs) { return lhs == rhs.m_details; }
bool operator==(const Foo& lhs, const FooDetails& rhs) {return lhs.m_details == rhs; }
bool operator<(const FooDetails& lhs, const Foo& rhs) { return lhs < rhs.m_details; }
bool operator<(const Foo& lhs, const FooDetails& rhs) { return lhs.m_details < rhs; }

int main() {
    std::vector<Foo> haystack = { Foo(5), Foo(6), Foo(7) };

    FooDetails needle(6);
    std::find(haystack.begin(), haystack.end(), needle);
    return 0;
}

And it successfully compiles. Your original version contains two errors:

  1. You try to create std::vector<Foo> initialising it with std::initialization_list<FooDetails>.
  2. You have provided too many comparison operators: both free versions and members of the Foo struct. So during lookup compiler complains that it doesn't know which one of them to choose. You should leave only one of them.

Upvotes: 4

Related Questions