कस्टम std का उपयोग करना :: तुलनित्र सेट करना


106

मैं पूर्णांक के सेट में वस्तुओं के डिफ़ॉल्ट क्रम को सांख्यिक के बजाय लेक्सिकोग्राफ़िक में बदलने का प्रयास कर रहा हूं, और मुझे जी ++ के साथ संकलन करने के लिए निम्नलिखित नहीं मिल सकता है:

असम्भव:

bool lex_compare(const int64_t &a, const int64_t &b) 
{
    stringstream s1,s2;
    s1 << a;
    s2 << b;
    return s1.str() < s2.str();
}

void foo()
{
    set<int64_t, lex_compare> s;
    s.insert(1);
    ...
}

मुझे निम्नलिखित त्रुटि मिलती है:

error: type/value mismatch at argument 2 in template parameter list for template<class _Key, class _Compare, class _Alloc> class std::set
error:   expected a type, got lex_compare

मैं क्या गलत कर रहा हूं?

जवाबों:


159

आप एक फ़ंक्शन का उपयोग कर रहे हैं, जहां आपको एक फ़ंक्टर (एक वर्ग जो ओवरलोड करता है) () ऑपरेटर का उपयोग करना चाहिए ताकि इसे फ़ंक्शन की तरह कहा जा सके)।

struct lex_compare {
    bool operator() (const int64_t& lhs, const int64_t& rhs) const {
        stringstream s1, s2;
        s1 << lhs;
        s2 << rhs;
        return s1.str() < s2.str();
    }
};

आप तब वर्ग का नाम टाइप पैरामीटर के रूप में उपयोग करते हैं

set<int64_t, lex_compare> s;

यदि आप functor boilerplate कोड से बचना चाहते हैं तो आप एक फ़ंक्शन पॉइंटर (मान lex_compareलेना एक फ़ंक्शन है) का उपयोग कर सकते हैं ।

set<int64_t, bool(*)(const int64_t& lhs, const int64_t& rhs)> s(&lex_compare);

4
@Omry: मुझे यह जानने में दिलचस्पी होगी कि आप किस कंपाइलर का उपयोग कर रहे हैं: codepad.org/IprafuVf

1
@Omry आप कौन से कंपाइलर का उपयोग कर रहे हैं?

4
@Omry C ++ मानक कहता है कि दूसरा टेम्पलेट पैरामीटर एक प्रकार का नाम होना चाहिए - एक फ़ंक्शन नाम एक प्रकार का नाम नहीं है।

6
फ़ंक्शन प्रकार को निरूपित करने के लिए क्या हम डिक्लेपट (lex_compare) का उपयोग कर सकते हैं?
लुईस चैन

2
@LewisChan सही शब्द होगाstd::set<int64_t, decltype(&lex_compare)> s(&lex_compare)
निशांत सिंह

111

1. आधुनिक सी ++ 20 समाधान

auto cmp = [](int a, int b) { return ... };
std::set<int, decltype(cmp)> s;

हम लैम्ब्डा फ़ंक्शन का उपयोग तुलनित्र के रूप में करते हैं। हमेशा की तरह, तुलनित्र को बूलियन मान वापस करना चाहिए, यह दर्शाता है कि पहले तर्क के रूप में पारित तत्व को परिभाषित करने वाले विशिष्ट सख्त कमजोर क्रम में दूसरे से पहले जाने के लिए माना जाता है या नहीं ।

ऑनलाइन डेमो

2. आधुनिक सी ++ 11 समाधान

auto cmp = [](int a, int b) { return ... };
std::set<int, decltype(cmp)> s(cmp);

C ++ 20 से पहले हमें लंबर को कंस्ट्रक्टर सेट करने के तर्क के रूप में पारित करना होगा

ऑनलाइन डेमो

3. पहले समाधान के समान, लेकिन लंबोदर के बजाय फ़ंक्शन के साथ

तुलनित्र को सामान्य बूलियन फ़ंक्शन के रूप में बनाएं

bool cmp(int a, int b) {
    return ...;
}

फिर इसका उपयोग इस तरह से करें:

std::set<int, decltype(cmp)*> s(cmp);

ऑनलाइन डेमो

या इस तरह:

std::set<int, decltype(&cmp)> s(&cmp);

ऑनलाइन डेमो

4. ()ऑपरेटर के साथ संरचना का उपयोग करके पुराना समाधान

struct cmp {
    bool operator() (int a, int b) const {
        return ...
    }
};

// ...
// later
std::set<int, cmp> s;

ऑनलाइन डेमो

5. वैकल्पिक समाधान: बूलियन फ़ंक्शन से संरचना बनाएं

बूलियन फ़ंक्शन लें

bool cmp(int a, int b) {
    return ...;
}

और इसका उपयोग करके संरचना बनाएं std::integral_constant

#include <type_traits>
using Cmp = std::integral_constant<decltype(&cmp), &cmp>;

अंत में, तुलनित्र का उपयोग तुलनित्र के रूप में करें

std::set<X, Cmp> set;

ऑनलाइन डेमो


3
उदाहरण 1 में, क्या cmp को कंस्ट्रक्टर में पारित करने की आवश्यकता है? क्या सेट का निर्माण स्वयं ही होगा क्योंकि लैम्बडा प्रकार को टेम्पलेट प्रकार के रूप में दिया जाता है?
पेटूका

2
C ++ 20 तुलनित्र से पहले @ पेकेतु को कंस्ट्रक्टर में पारित किया जाना है। सी ++ में बिना तर्क के 20 कंस्ट्रक्टर का उपयोग किया जा सकता है। प्रश्न के लिए धन्यवाद; उत्तर अपडेट किया गया था
diralik

1
@diralik आपके पहले से ही शानदार जवाब के लिए प्रतिक्रिया और अपडेट के लिए बहुत-बहुत धन्यवाद।
पेटीके

1
जेनेरिक लैंबडा 1 और 2 के लिए भी काम करता है
ZFY

2
वह 5. पागल है। हर दिन भाषा के नए नुक्कड़ और सारस मिलते हैं।
जान होशेक

18

याकोबी का जवाब मुझे फनकार बॉयलरप्लेट को एनकैप्सुलेट करने के लिए एक एडेप्टर लिखने के लिए प्रेरित करता है।

template< class T, bool (*comp)( T const &, T const & ) >
class set_funcomp {
    struct ftor {
        bool operator()( T const &l, T const &r )
            { return comp( l, r ); }
    };
public:
    typedef std::set< T, ftor > t;
};

// usage

bool my_comparison( foo const &l, foo const &r );
set_funcomp< foo, my_comparison >::t boo; // just the way you want it!

वाह, मुझे लगता है कि मुसीबत के लायक था!


17
एक राय का मामला है, मुझे लगता है।

6

आप एक फंक्शन तुलनित्र को बिना लपेटे उपयोग कर सकते हैं:

bool comparator(const MyType &lhs, const MyType &rhs)
{
    return [...];
}

std::set<MyType, bool(*)(const MyType&, const MyType&)> mySet(&comparator);

जो हर बार आपको उस प्रकार के सेट की आवश्यकता के लिए परेशान कर रहा है, और यदि आप एक ही तुलनित्र के साथ सभी सेट नहीं बनाते हैं, तो समस्या हो सकती है।


3

std::less<> के साथ कस्टम कक्षाओं का उपयोग करते समय operator<

यदि आप अपने कस्टम वर्ग के एक सेट के साथ काम कर रहे हैं जिसे operator<परिभाषित किया गया है, तो आप बस उपयोग कर सकते हैं std::less<>

जैसा कि http://en.cppreference.com/w/cpp/container/set/find C ++ 14 में बताया गया है, दो नए findएपीआई जोड़े गए हैं:

template< class K > iterator find( const K& x );
template< class K > const_iterator find( const K& x ) const;

जो आपको करने की अनुमति देता है:

main.cpp

#include <cassert>
#include <set>

class Point {
    public:
        // Note that there is _no_ conversion constructor,
        // everything is done at the template level without
        // intermediate object creation.
        //Point(int x) : x(x) {}
        Point(int x, int y) : x(x), y(y) {}
        int x;
        int y;
};
bool operator<(const Point& c, int x) { return c.x < x; }
bool operator<(int x, const Point& c) { return x < c.x; }
bool operator<(const Point& c, const Point& d) {
    return c.x < d;
}

int main() {
    std::set<Point, std::less<>> s;
    s.insert(Point(1, -1));
    s.insert(Point(2, -2));
    s.insert(Point(0,  0));
    s.insert(Point(3, -3));
    assert(s.find(0)->y ==  0);
    assert(s.find(1)->y == -1);
    assert(s.find(2)->y == -2);
    assert(s.find(3)->y == -3);
    // Ignore 1234, find 1.
    assert(s.find(Point(1, 1234))->y == -1);
}

संकलित करें और चलाएं:

g++ -std=c++14 -Wall -Wextra -pedantic -o main.out main.cpp
./main.out

के बारे में अधिक जानकारी std::less<>पर पाया जा सकता है: पारदर्शी तुलनित्र क्या हैं?

उबंटू 16.10, g++6.2.0 पर परीक्षण किया गया ।

हमारी साइट का प्रयोग करके, आप स्वीकार करते हैं कि आपने हमारी Cookie Policy और निजता नीति को पढ़ और समझा लिया है।
Licensed under cc by-sa 3.0 with attribution required.