3

I have code that works just fine, in a local function:

struct Divider
{
public:
    size_t factor;
    size_t next;
};

void foo()
{
    auto cmp = [](const Divider& x, const Divider& y) { return x.next > y.next; };
    std::priority_queue < Divider, std::vector<Divider>, decltype(cmp)> sieve(cmp);
    // ...
}

I would now like to move my sieve variable into a class. I can write the following monstrosity:

class Bar
{
    inline static auto cmp = [](const Divider& x, const Divider& y) { return x.next > y.next; };
    std::priority_queue < Divider, std::vector<Divider>, decltype(cmp)> sieve = std::priority_queue < Divider, std::vector<Divider>, decltype(cmp)>(cmp);
};

Is there any way I can write this default construction without specifying the type twice? Or just in a cleaner fashion.

JeJo
  • 30,635
  • 6
  • 49
  • 88
Jeffrey
  • 11,063
  • 1
  • 21
  • 42
  • 3
    Why? Why does this need to be a lambda? Is `struct SomeName { auto operator() ... };` really so verbose? – Nicol Bolas Nov 05 '19 at 18:12
  • 2
    i dont get the downvotes, OP maybe went into the wrong direction, maybe it is a xy-problem, but both x and y are clear and the question contains everything that it needs to be answered – 463035818_is_not_an_ai Nov 05 '19 at 18:15
  • ..maybe I was just too fast in interpreting something into nothing ;) – 463035818_is_not_an_ai Nov 05 '19 at 18:18
  • @nicol, yeah, I could use operator() in the `Divider` struct, but I have other compare functions for the same struct. – Jeffrey Nov 05 '19 at 18:19
  • @Jeffrey: "*I could use operator() in the Divider struct*" That's not what I meant. I meant that `SomeName` would be an object distinct from `Divider`, and you would pass `SomeName` to the `priority_queue` in question. Using a lambda only saves a very few keystrokes; what's the point? – Nicol Bolas Nov 05 '19 at 19:56

2 Answers2

6

Is there any way I can write this default construction without specifying the type twice?

Yes, you can!

Use braced-init-list(or uniform-initiation) to initlize the std::priority_queue member of Bar class.

class Bar
{
    inline static auto cmp
        = [](const Divider& x, const Divider& y) { return x.next > y.next; };
    std::priority_queue<Divider, std::vector<Divider>, decltype(cmp)> sieve{ cmp };
           //                                                          ^^^^^^^^^^^^^ >> like this
};

Or simply provide a compare functor, by which you can avoid passing the comparator object to the constructor of the std::priority_queue.

class Bar
{
    struct Compare final // compare functor
    {
        bool operator()(const Divider& x, const Divider& y) const { 
            return x.next > y.next;
        }
    };
    std::priority_queue<Divider, std::vector<Divider>, Compare> sieve;
    //                                                 ^^^^^^^^^^^^^^^^^ >> like this
};
JeJo
  • 30,635
  • 6
  • 49
  • 88
2

For the sake of completeness and to provide an answer that takes the question in the title literally, you can let a member function return the lambda:

#include <iostream>

struct Bar {
    auto get_compare(){
        return [](){ std::cout << "hello world";};
    }
};

int main(){
    Bar b;
    b.get_compare()();
}

I'd use this when the lambda cannot be static. Though, for the code you posted I'd surely prefer the solution with the lambda as static member and de-monstrositizing the code by using uniform initialization (as outlined in the other answer).

463035818_is_not_an_ai
  • 109,796
  • 11
  • 89
  • 185