Тип подписи объекта функции сравнения - PullRequest
1 голос
/ 28 марта 2020

Как я могу использовать тип объекта функции сравнения в сигнатуре метода? Например, все в порядке:

struct compInt {
    bool operator() (const int a, const int b) { return a < b; }
};  

set<int,compInt> s1; 

// Actually this is no good, but removing it would obfuscate
// the accepted answer:
set<int> s2(compInt);  

[Последний компилируется, но это объявление функции, s2 оказывается не контейнером] .

Но я хочу сделать это:

void func (____ x)
{
    set<int> s(x);
}

Я не хочу этого делать:

template<typename C>
void func (C& c)
{
    set<int> s(c);
}

И function<bool(const int,const int)> не работает. Я попытался сделать compInt::operator() виртуальным, чтобы я мог сделать это:

void func (compInt& ci)

И передать производные объекты, но на самом деле set<int> s(ci) затем не удается скомпилировать (за что я почти благодарен, потому что это ужасный хак).

Ответы [ 2 ]

1 голос
/ 28 марта 2020
set<int> s1(compInt);

Здесь объявляется функция с типом возвращаемого значения set<int>.

set<int> s(x);

Объявляется локальная переменная типа set<int>. Тип компаратора не выводится из аргумента, а вместо этого используется аргумент шаблона по умолчанию. Таким образом, compInt не используется в качестве компаратора, поэтому вы не можете передать экземпляр compInt в конструктор.

Вы можете использовать:

void func (compInt x)
{
    std::set<int,compInt> s(x);

I попытался сделать compInt :: operator () виртуальным, чтобы я мог сделать это:

void func (compInt& ci)

Polymorphi c компаратор был бы весьма проблематичным c. Set хранит объект по значению, поэтому переход в функцию по ссылке не поможет. Вам нужно будет использовать стирание типа: определите компаратор оболочки, который принимает компаратор polymorphi c в качестве аргумента конструктора, сохраняет его в хранилище dynamici c и делегирует оператор вызова хранимому компаратору polymorphi c. Затем используйте тип оболочки в качестве аргумента шаблона набора.

0 голосов
/ 28 марта 2020

Eeroiki заставил меня идти в правильном направлении. В конечном итоге я остановился на этом (обратите внимание, что сравниваемые объекты на самом деле не являются целочисленными, и к ним можно применить широкий диапазон компараторов).

using intCompFunc = std::function<bool(const int,const int)> 

struct compInt {
    intCompFunc comp;
    bool operator() (const int a, const int b) const {
        return comp(a, b);
}

void foo (intCompfunc icf)
{ 
    compInt ci { icf };
    std::set<int,compInt> s1(ci);
}    

Что означает, что пользователь может передать любой вид функтора, например лямбда:

foo([] (const int a, const int b) { return a < b; }); 

Моя путаница проистекает из-за того, почему это не так, во-первых, что я считаю действительно исторической проблемой (не было функторов C ++ 11, когда был написан STL ). OTOH, использование базового типа вместо параметра шаблона приводит к некоторым накладным расходам во время выполнения.

...