How to use lambda expression as a template parameter? E.g. as a comparison class initializing a std::set.
The following solution should work, as lambda expression merely creates an anonymous struct, which should be appropriate as a template parameter. However, a lot of errors are spawned.
Code example:
struct A {int x; int y;};
std::set <A, [](const A lhs, const A &rhs) ->bool {
return lhs.x < rhs.x;
} > SetOfA;
Error output (I am using g++ 4.5.1 compiler and --std=c++0x compilation flag):
error: ‘lhs’ cannot appear in a constant-expression
error: ‘.’ cannot appear in a constant-expression
error: ‘rhs’ cannot appear in a constant-expression
error: ‘.’ cannot appear in a constant-expression
At global scope:
error: template argument 2 is invalid
Is that the expected behavior or a bug in GCC?
EDIT
As someone pointed out, I'm using lambda expressions incorrectly as they return an instance of the anonymous struct they are referring to.
However, fixing that error does not solve the problem. I get lambda-expression in unevaluated context error for the following code:
struct A {int x; int y;};
typedef decltype ([](const A lhs, const A &rhs) ->bool {
return lhs.x < rhs.x;
}) Comp;
std::set <A, Comp > SetOfA;
The 2nd template parameter of std::set expects a type, not an expression, so it is just you are using it wrongly.
You could create the set like this:
auto comp = [](const A& lhs, const A& rhs) -> bool { return lhs.x < rhs.x; };
auto SetOfA = std::set <A, decltype(comp)> (comp);
For comparators used this way, you're still better off with a non-0x approach:
struct A { int x; int y; };
struct cmp_by_x {
bool operator()(A const &a, A const &b) {
return a.x < b.x;
}
};
std::set<A, cmp_by_x> set_of_a;
However, in 0x you can make cmp_by_x a local type (i.e. define it inside a function) when that is more convenient, which is forbidden by current C++.
Also, your comparison treats A(x=1, y=1) and A(x=1, y=2) as equivalent. If that's not desired, you need to include the other values that contribute to uniqueness:
struct cmp_by_x {
bool operator()(A const &a, A const &b) {
return a.x < b.x || (a.x == b.x && a.y < b.y);
}
};
Not sure if this is what you're asking, but the signature of a lambda which returns RetType and accepts InType will be:
std::function<RetType(InType)>
(Make sure to #include <functional>)
You can shorten that by using a typedef, but I'm not sure you can use decltype to avoid figuring out the actual type (since lambdas apparently can't be used in that context.)
So your typedef should be:
typedef std::function<bool(const A &lhs, const A &rhs)> Comp
or
using Comp = std::function<bool(const A &lhs, const A &rhs)>;
the problem is the last template parameter is type not an object, so you might want to do the following
std::set <A, std::fuction<bool(const A &,const A &)>>
SetOfA([](const A lhs, const A &rhs) ->bool {
return lhs.x < rhs.x;
} > SetOfA;
to make it simpler you can do the following:
auto func = SetOfA([](const A lhs, const A &rhs) ->bool { return lhs.x < rhs.x;}
set <A,decltype(func)> SetOfA(func);
cheers
Related
It works for the struct xy that I declared. Why doesn't the same pattern work for complex<int>?
#include <complex>
#include <set>
using namespace std;
struct xy {
int x, y;
};
bool operator< (const xy &a, const xy &b) {
return a.x < b.x;
}
bool operator< (const complex<int> &a, const complex<int> &b) {
return a.real() < b.real();
}
int main() {
xy q;
set<xy> s;
s.insert(q);
complex<int> p;
set< complex<int> > t; //If I comment out these two lines,
t.insert(p); //it compiles fine.
return 0;
}
The error message:
In file included from c:\m\lib\gcc\mingw32\4.8.1\include\c++\string:48:0,
from c:\m\lib\gcc\mingw32\4.8.1\include\c++\bits\locale_classes.h:40,
from c:\m\lib\gcc\mingw32\4.8.1\include\c++\bits\ios_base.h:41,
from c:\m\lib\gcc\mingw32\4.8.1\include\c++\ios:42,
from c:\m\lib\gcc\mingw32\4.8.1\include\c++\istream:38,
from c:\m\lib\gcc\mingw32\4.8.1\include\c++\sstream:38,
from c:\m\lib\gcc\mingw32\4.8.1\include\c++\complex:45,
from test.cpp:1:
c:\m\lib\gcc\mingw32\4.8.1\include\c++\bits\stl_function.h: In instantiation of 'bool less<>::operator()(const _Tp&, const _Tp&) const':
c:\m\lib\gcc\mingw32\4.8.1\include\c++\bits\stl_tree.h:1321:11: required from 'pair<> _Rb_tree<>::_M_get_insert_unique_pos(const key_type&)'
c:\m\lib\gcc\mingw32\4.8.1\include\c++\bits\stl_tree.h:1374:47: required from 'pair<> _Rb_tree<>::_M_insert_unique(_Arg&&)'
c:\m\lib\gcc\mingw32\4.8.1\include\c++\bits\stl_set.h:463:29: required from 'pair<> __cxx1998::set<>::insert(const value_type&)'
c:\m\lib\gcc\mingw32\4.8.1\include\c++\debug\set.h:220:59: required from 'pair<> __debug::set<>::insert(const value_type&)'
test.cpp:28:19: required from here
c:\m\lib\gcc\mingw32\4.8.1\include\c++\bits\stl_function.h:235:20:
error: no match for 'operator<' (operand types are 'const std::complex<int>' and 'const std::complex<int>')
{ return __x < __y; }
My best guess is that this has something to do with complex<T> being a class, not a struct. By I can't see the logic of why that should make a difference. Or is it some template horribleness?
What I see happening is that the STL at some point tries (roughly speaking) to do a < b, where a and b are complex<int> instances. So it's looking for bool operator< (const complex<int> &a, const complex<int> &b). Well, there is exactly that declared just above main(). Why is it being unreasonable? I thought maybe it didn't like them being references. But removing the ampersands made no difference to its complaint.
One option is to write a custom comparison functor, and instantiate the set with this.
#include <complex>
#include <set>
bool operator< (const std::complex<int> &a, const std::complex<int> &b) {
return a.real() < b.real();
}
struct my_less {
bool operator() (const std::complex<int>& lhs, const std::complex<int>& rhs) const{
return lhs < rhs;
}
};
int main() {
std::complex<int> p;
std::set< std::complex<int>, my_less > t;
t.insert(p);
return 0;
}
Sample on Coliru
It works for the struct xy that I declared. Why doesn't the same pattern work for complex<int>?
The reason is that when you use types from namespace std only, like std::set and std::complex, the compiler has no reason to look for operators in any other namespaces.
With struct xy this is different, as the operator is declared together with the type.
And also, the current standard says:
The effect of instantiating the template complex for any type other than float, double, or long double is
unspecified.
So using complex<int> might, or might not, work depending on which compiler you use. "Unspecified" is not as bad as "undefined", but
of course not very reliable or portable.
As of today, I am facing this issue with my Ubuntu's g++. Suppose I have:
namespace X { namespace Y { class C { ... }; } }
Now operator== is recognized if it's defined in a global namespace, such as:
bool operator== (const X::Y::C& lhs, const X::Y::C& rhs) { return lhs == rhs; }
However, somehow compiler doesn't recognize operator<, if defined in the same way.
Now following way works well:
namespace X { namespace Y {
bool operator< (const C& lhs, const C& rhs) { return lhs < rhs; } } }
However, whether you should do it the same with expanding standard namespace std is a controversial topic. :-)
The following program aborts:
#include <boost/variant.hpp>
using variant_type = boost::variant< int&, std::string& >;
int main () {
int a, b;
variant_type v (a), u (b);
v == u;
return 0;
}
with:
$ g++ -std=c++14 t.cpp && ./a.out
a.out: /opt/boost/default/include/boost/variant/detail/forced_return.hpp:39: T boost::detail::variant::forced_return() [with T = const int&]: Assertion `false' failed.
Aborted (core dumped)
AFAICT you can't compare for equality between variants of non-const references because of a wrong overload of operator function-call being selected in class known_get. known_get is instantiated for const T in the comparer visitor instead of what seems should have been T (variant.hpp:905 in v1.59.0).
Am I missing something?
I think this is a Boost bug.
The type requirements here are:
CopyConstructible or MoveConstructible.
Destructor upholds the no-throw exception-safety guarantee.
Complete at the point of variant template instantiation. (See boost::recursive_wrapper<T> for a type wrapper that accepts incomplete types to enable recursive variant types.)
as well as:
EqualityComparable: variant is itself EqualityComparable if and only if every one of its bounded types meets the requirements of the concept.
A reference type is copy constructible, is no-throw destructible, complete, and equality comparable. So we're good on all points there. The issue is that the the visitor used in the implementation is:
template <typename T>
bool operator()(const T& rhs_content) const
{
// Since the precondition ensures lhs and rhs types are same, get T...
known_get<const T> getter;
const T& lhs_content = lhs_.apply_visitor(getter);
// ...and compare lhs and rhs contents:
return Comp()(lhs_content, rhs_content);
}
That is, we're using const T as the known getter. This is fine for non-reference types, but incorrect for reference types, since known_get asserts if it gets the wrong type:
T& operator()(T& operand) const BOOST_NOEXCEPT
{
return operand;
}
template <typename U>
T& operator()(U& ) const
{
// logical error to be here: see precondition above
BOOST_ASSERT(false);
return ::boost::detail::variant::forced_return<T&>();
}
With int&, those overloads become:
const int& operator()(const int& ) const;
const int& operator()(int& ) const; [ U = int ]
The second overload is preferred since the type it refers to would be less const-qualified than the non-template overload. That's why you get the assert, and this behavior is clearly incorrect. We should be able to compare references!
The simpler solution would be to drop the consts from comparer and simply use:
template <typename T>
bool operator()(T& rhs_content) const
{
known_get<T> getter;
T& lhs_content = lhs_.apply_visitor(getter);
return Comp()(lhs_content, rhs_content);
}
This would work for reference types as well as const types.
ok, I had a think about this (and another look at the documentation).
The synopsis for boost::variant does not show an operator== being defined for a variant.
This leads me to suggest that the correct approach for comparison is via a binary visitor.
here is your (modified) code again, which compiles on my machine (apple clang) your code crashed my compiler too.
#include <string>
#include <boost/variant.hpp>
using variant_type = boost::variant< int&, std::string& >;
struct is_equal
{
// compare int with int
bool operator()(const int& l, const int& r) const {
return l == r;
}
// compare string with string
bool operator()(const std::string& l, const std::string& r) const {
return l == r;
}
// anything else compared with anything else compares false.
template<class X, class Y>
bool operator()(const X&, const Y&) const {
return false;
}
};
int main () {
int a = 0, b = 0;
variant_type v = a, u = b;
bool ok = boost::apply_visitor(is_equal(), v, u);
// bool ok = (v == u);
return 0;
}
I have a code in C++14. However, when I used it in C++11, it has an error at const auto. How to use it in C++11?
vector<vector <int> > P;
std::vector<double> f;
vector< pair<double, vector<int> > > X;
for (int i=0;i<N;i++)
X.push_back(make_pair(f[i],P[i]));
////Sorting fitness descending order
stable_sort(X.rbegin(), X.rend());
std::stable_sort(X.rbegin(), X.rend(),
[](const auto&lhs, const auto& rhs) { return lhs.first < rhs.first; });
C++11 doesn't support generic lambdas. That's what auto in the lambda's parameter list actually stands for: a generic parameter, comparable to parameters in a function template. (Note that the const isn't the problem here.)
Note: C++14 does support lambdas with auto, const auto, etc. You can read about it here.
You have basically two options:
Type out the correct type instead of auto. Here it is the element type of X, which is pair<double, vector<int>>. If you find this unreadable, a typedef can help.
std::stable_sort(X.rbegin(), X.rend(),
[](const pair<double, vector<int>> & lhs,
const pair<double, vector<int>> & rhs)
{ return lhs.first < rhs.first; });
Replace the lambda with a functor which has a call operator template. That's how generic lambdas are basically implemented behind the scene. The lambda is very generic, so consider putting it in some global utility header. (However do not using namespace std; but type out std:: in case you put it in a header.)
struct CompareFirst {
template <class Fst, class Snd>
bool operator()(const pair<Fst,Snd>& l, const pair<Fst,Snd>& r) const {
return l.first < r.first;
}
};
std::stable_sort(X.rbegin(), X.rend(), CompareFirst());
I know there is an accepted answer, but you can also use decltype in C++11 for this, it looks a bit messy...
stable_sort(X.rbegin(), X.rend(), [](decltype(*X.cbegin()) lhs, decltype(lhs) rhs) { return lhs.first < rhs.first; });
Use cbegin() here as you get the const correct value_type of the container.
Unfortunately, generic lambdas that take auto (whether const or not) is a C++14 only feature.
See here https://isocpp.org/wiki/faq/cpp14-language#generic-lambdas for some more details.
Alternatively you can directly use the value_type typedef of the container with a decltype, like
std::stable_sort(X.rbegin(), X.rend(),
[](const decltype(X)::value_type & lhs,
const decltype(X)::value_type & rhs)
{return lhs.first < rhs.first; }
);
const auto is not supported in C++11 as a lambda parameter (actually generic lambdas are not supported in C++11).
To fix:
using pair_type = std::pair<double, std::vector<int>>;
vector<pair_type> X;
std::stable_sort(X.rbegin(), X.rend(),
[](const pair_type&lhs, const pair_type& rhs)
{ return lhs.first < rhs.first; });
Trying to brush up on my C++ and STL proficiency, running into a problem with std::map keyed by a structure I've defined. Relevant code:
typedef struct key_t {
int a;
int b;
bool operator==(const key_t& rhs)
{
return (a == rhs.a) && (b == rhs.b);
}
bool operator<(const key_t& rhs) //added the when I saw this error, didn't help
{
return a < rhs.a;
}
} key_t;
std::map<key_t, int> fooMap;
void func(void)
{
key_t key;
key.a = 1;
key.b = 2;
fooMap.insert(std::pair<key_t, int>(key, 100));
}
Error looks like this:
"/opt/[redacted]/include/functional", line 133: error: no operator "<" matches these operands
operand types are: const key_t < const key_t
detected during:
instantiation of "bool std::less<_Ty>::operator()(const _Ty &, const _Ty &) const [with _Ty=key_t]" at line 547 of "/opt/[redacted]/include/xtree"
instantiation of "std::_Tree<_Traits>::_Pairib std::_Tree<_Traits>::insert(const std::_Tree<_Traits>::value_type &) [with _Traits=std::_Tmap_traits<key_t, UI32, std::less<key_t>, std::allocator<std::pair<const key_t, UI32>>, false>]"
What am I doing wrong? Is it just flat-out awful/impossible to use structures as a map key? Or something else I'm overlooking?
This
bool operator<(const key_t& rhs)
needs to be a const method
bool operator<(const key_t& rhs) const
The two are different signatures, and std::less looks for the latter. The latter, as a const method, implying that it won't modify the object. The former however without const may imply that a modification to this may be performed.
In general its a good idea to have const methods, even if you can cast in away, it implies a promise to the client that no modifications will take place.
For starters, the operators have to be const. (And you don't need the == operator.)
And where did you learn to use a typedef for a struct. There's no reason for it.
And finally, if you want both elements to participate as part of
the key, you'll have to compare both of them:
struct Key
{
int a;
int b;
bool operator<( Key const& rhs ) const
{
return a < rhs.a
|| ( !(rhs.a < a) && b < rhs.b );
}
};
Otherwise, Key( 1, 2 ) and Key( 1, 3 ) will effectively be
equal.
I'm having an array of structure containing three fields:
struct data{
int s;
int f;
int w;
};
struct data a[n];
In order to sort the array of structure based on field f I'm using my own comparison operator :
bool myf( struct data d1,const struct data d2){
return d1.f < d2.f ;
}
The above operator works fine in inbuilt sort() function :
sort(a,a+n,myf);
but it's not working for upper_bound() function :
upper_bound(a,a+n,someValue,myf);
Can anyone tell me where am I doing wrong ? Is my comparison operator wrong ? If it's wrong, why is it working for sort() function and not upper_bound() ?
I'm getting following on compilation :
/usr/lib/gcc/i686-pc-linux-gnu/4.3.4/include/g++-v4/bits/stl_algo.h: In function ‘_FIter std::upper_bound(_FIter, _FIter, const _Tp&, _Compare) [with _FIter = data*, _Tp = int, _Compare = bool (*)(data, data)]’:
prog.cpp:37: instantiated from here
/usr/lib/gcc/i686-pc-linux-gnu/4.3.4/include/g++-v4/bits/stl_algo.h:2243: error: conversion from ‘const int’ to non-scalar type ‘data’ requested
All you actually need here is to create operator< for your type:
inline bool operator<( const data& lhs, const data& rhs ) {
return lhs.f < rhs.f;
}
and standard algorithms will magically work for you.
In C++ you don't need struct when referring to a type like in C, and you want to pass by const reference to avoid copying.
Edit 0:
The above overloads standard comparison operator < for your type. You would use it implicitly as:
data values[N];
// ... populate
std::sort( values, values + N );
or explicitly with a standard functor:
std::sort( values, values + N, std::less<data>());
Edit 1:
See that compiler tells you _Tp = int in the warning? You need to pass an instance of data as third argument to upper_bound, not int:
data xxx = { 0, 1, 7 };
auto iter = std::upper_bound( values, values + N, xxx );
You can also create overloads for comparing to integers, like:
inline bool operator<( const data& lhs, int rhs ) {
return lhs.f < rhs;
}
inline bool operator<( int lhs, const data& rhs ) {
return lhs < rhs.f;
}
for your original invocation to work.
Primarily, it isn't working because the upper_bound overload that accepts a custom sorting takes four parameters:
// http://en.cppreference.com/w/cpp/algorithm/upper_bound
template< class ForwardIt, class T, class Compare >
ForwardIt upper_bound( ForwardIt first, ForwardIt last, const T& value,
Compare comp );
It was suggested in another answer that you introduce operator< for your type. However, do not do this just for the sake of one specific sorting. Only introduce comparison operators iff they actually make sense for your type.
If you don't follow this rule, future programmers might use your type and wonder about why something works that shouldn't, or vice versa. Your future evil twin may also want to use another sorting for his purpose.
E.g., it makes sense for a complex-datatype class, a SIMD-class (like std::valarray), but it doesn't make any specific sense for example for an Employee class:
Employee foo, bar;
if (bar > foo) {
// is bar taller than foo?
// is bar older than foo?
// is bar working better than foo?
// is bar bigger newbie than foo?
}
Instead, you could do it like this:
namespace employee_ordering {
struct by_name_ascending {
bool operator() (Employee const &lhs, Employee const &rhs) const {
return lhs.name() < rhs.name();
}
};
struct by_name_descending {
bool operator() (Employee const &lhs, Employee const &rhs) const {
return lhs.name() > rhs.name();
}
}
};
....
upper_bound(first, last, ..., employee_ordering::by_name_ascending());