This question already has answers here:
Closed 6 years ago.
I came across the following code here, which is from the C++ implementation of Dijkstra algorithm using an adjacency matrix.
//read in edges keeping only the minimum
for(int i=0; i<E; i++) {
int v1,v2,tmp;
fin >> v1; fin >> v2;
fin >> tmp;
adjmat[v1][v2]<?=tmp; // <?= sets left to min(left,right)
adjmat[v2][v1]<?=tmp;
}
Pay attention to the last two lines, which apply operator <?=
. As being commented, the following line
adjmat[v1][v2]<?=tmp; // <?= sets left to min(left,right)
will set left
to min(left,right)
.
I never see this operator before. I tried the code in VS, it can not compile. What is it? How can it set left
to be min(left,right)
?
It is an old GCC extension; it does what it says in the comment (it's the compound assignment form of the "minimum" operator). This is not standard C++.
The difference between a = a < b ? a : b
and a <?= b
is that the latter only evaluates each operand once.
In modern standard C++, I believe you could write an "assign the minimum" algorithm like this:
auto && __a = a;
auto && __b = b;
if (!(__a < __b)) { __a = std::forward<decltype(__b)>(__b); }
This should be the body of a macro which has the effect of a <?= b
, and a
and b
are arbitrary expressions, potentially with side effects. Or you could wrap it into a template:
template <typename T,
typename U,
typename P = std::less<std::common_type_t<std::decay_t<T>, std::decay_t<U>>>
T && clamp_to_minimum(T && a, U && b, P p = P())
{
if (!(p(a, b))) { a = std::forward<U>(b); }
return std::forward<T>(a);
}
It is equivalent to:
adjmat[v1][v2] = (adjmat[v1][v2]<tmp)? adjmat[v1][v2] : tmp;
In general:
a OP ?= b;
<=> a = (a OP b)? a : b;
A little example (compiled using MingW2.95 and C-Free IDE on Windows) showing what @Kerrek SB said: the GCC extension evalute operands only once, which it's nice
#include <stdio.h>
int f(int x)
{
printf ("Calling f() with x=%d\n", x);
return x*x;
}
int main()
{
int a,b,c;
printf ("A and B? ");
scanf ("%d%d", &a, &b);
c = a;
a = (a<f(b))? a : f(b);
printf ("A using ternary operator: %d\n", a);
a = c;
a <?= f(b);
printf ("A using weird GCC extension: %d\n", a);
return 0;
}
A and B? 3 1
Calling f() with x=1
Calling f() with x=1
A using ternary operator: 1
Calling f() with x=1
A using weird GCC extension: 1