I have a Dijkstra
class which uses a priority_queue
with a custom compare function. I named the queue DijkstraPriorityQueue
with a using
statement. Inside the class constructor, I initialize the queue. To do that, I give the compare function in a lambda expression.
For the first queue, PQ1
, the compare function is { return distTo[u] > distTo[v]; }
{ return distTo[u] > distTo[v]; }
and this compiles fine, because the vector<float> distTo
is a member of the class.
But for the second queue, PQ2
, the function is { return distTo2[u] > distTo2[v]; }
{ return distTo2[u] > distTo2[v]; }
where vector<float> distTo2
is just a temporary variable inside the constructor, and that doesn't compile. (I think that's the reason at least)
Also, I randomly tried to change vector<float> distTo2
to static vector<float> distTo2
by intuition and it compiles, however I don't think this is what I want to be doing. I am not familiar with static variables inside functions, since that doesn't exist in Java or C#. At any case, what is a clean solution to make the code below compile and work as intended ?
Dijkstra.h
class Dijkstra
{
public:
Dijkstra();
~Dijkstra();
private:
vector<float> distTo;
};
Dijkstra.cpp
using DijkstraPriorityQueue = priority_queue<int, vector<int>, function<bool(int, int)>>;
Dijkstra::Dijkstra()
{
distTo = vector<float>(V, FLT_MAX);
// Compiles fine
DijkstraPriorityQueue PQ1 = DijkstraPriorityQueue([this](int u, int v)
{ return distTo[u] > distTo[v]; });
vector<float> distTo2 = vector<float>(V, FLT_MAX);
// Doesn't compile
DijkstraPriorityQueue PQ2 = DijkstraPriorityQueue([this](int u, int v)
{ return distTo2[u] > distTo2[v]; });
}
Edit:
The following code compiles too. Any clues why ? Can someone explain what capture is on lambda expressions ? Or how should I write my code properly in this specific case ?
DijkstraPriorityQueue PQ2 = DijkstraPriorityQueue([distTo2](int u, int v)
{ return distTo2[u] > distTo2[v]; });
There are two main aspects of your question:
What is this “capture” thing, and why the error?
How to specify a custom compare function for a priority queue?
These aspects are most cleanly discussed separately.
Unfortunately the presented (incomplete) example code is not well suited for discussing either aspect, so I just disregard it.
Consider the following code:
#include <stdio.h>
struct S
{
int a_;
void foo() const
{
// Compiles nicely:
[this]() -> void { printf( "%d\n", a_ ); }();
// Doesn't compile, oh why!:
int b = 666;
[this]() -> void { printf( "%d\n", b ); }();
}
};
auto main()
-> int
{ S{ 42 }.foo(); }
MinGW g++ 5.1.0 provides the following diagnostics (compilation errors):
x1.cpp: In lambda function: x1.cpp:14:44: error: 'b' is not captured [this]() -> void { printf( "%d\n", b ); }(); ^ x1.cpp:14:14: note: the lambda has no capture-default [this]() -> void { printf( "%d\n", b ); }(); ^ x1.cpp:13:13: note: 'int b' declared here int b = 666; ^
To understand the “not captured”, let's implement the lambdas manually , just doing a code transformation equivalent to what the compiler does with it:
void foo() const
{
// Compiles nicely:
//[this]() -> void { printf( "%d\n", a_ ); }();
class Functor_a
{
private:
S const* captured_this_;
public:
void operator()()
{ printf( "%d\n", captured_this_->a_ ); }
Functor_a( S const* this_capture )
: captured_this_( this_capture )
{}
};
Functor_a f_a{ this };
f_a();
// Doesn't compile, oh why!:
int b = 666;
// [this]() -> void { printf( "%d\n", b ); }();
class Functor_b
{
private:
S const* captured_this_;
public:
void operator()()
{ printf( "%d\n", b ); }
Functor_b( S const* this_capture )
: captured_this_( this_capture )
{}
};
Functor_b f_b{ this };
f_b();
}
};
The diagnostic is now more clear. Since Functor_b
is a class, and since a class in C++ is completely free-standing entity, its code has no relation to or access to things in a particular invocation of foo()
. So the compiler doesn't accept the reference to some unspecified b
, but notes that if you really meant the b
in the containing scope, then hey, that name b
refers to a different variable in each call of foo
, and isn't a valid choice:
x2.cpp: In member function 'void S::foo() const::Functor_b::operator()()': x2.cpp:37:35: error: use of local variable with automatic storage from containing function { printf( "%d\n", b ); } ^ x2.cpp:28:17: note: 'int b' declared here int b = 666; ^
One solution is to capture the value , ie copy it into the functor class instance, eg as follows:
class Functor_b
{
private:
int const captured_b_;
public:
void operator()()
{ printf( "%d\n", captured_b_ ); }
Functor_b( int const b_capture )
: captured_b_( b_capture )
{}
};
Functor_b f_b{ b }; // ← The capture.
f_b(); // ← Using the captured value.
Alternatively you could capture a pointer to the variable, capture by reference . In that the case the pointer is only valid for the lifetime of the variable. So you'd better not keep a functor instance around after that.
Expressed in lambda notation the capture of the value can look like this:
[b]() -> void { printf( "%d\n", b ); }();
Or like this, with a general capture-whatever's-needed-by-value =
:
[=]() -> void { printf( "%d\n", b ); }();
Capturing by reference, ie a pointer, looks like this:
[&]() -> void { printf( "%d\n", b ); }();
std::priority_queue
. Eg like this:
#include <iostream>
#include <string>
#include <queue>
#include <vector>
using namespace std;
struct S
{
string name;
int birth_year;
};
auto main() -> int
{
struct Age_sort
{
auto operator()( S const& a, S const& b )
-> bool
{ return (a.birth_year < b.birth_year); }
};
using Q = priority_queue< S, vector<S>, Age_sort >;
Q pq;
pq.push( S{ "beta", 1980 } );
pq.push( S{ "alfa", 1992 } );
pq.push( S{ "charlie", 1971 } );
while( not pq.empty() )
{
cout << pq.top().name << ' ' << pq.top().birth_year << endl;
pq.pop();
}
}
The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.