开发者

How to use a lambda expression as a template parameter?

开发者 https://www.devze.com 2023-01-17 16:53 出处:网络
How to use lambda expression as a template parameter? E.g. as a comparison class initializing a std::set.

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;
    }开发者_Python百科) 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

0

精彩评论

暂无评论...
验证码 换一张
取 消

关注公众号