Pertanyaan Bagaimana cara menggunakan ekspresi lambda sebagai parameter template?


Bagaimana cara menggunakan ekspresi lambda sebagai parameter template? Misalnya. sebagai kelas pembanding yang menginisialisasi std :: set.

Solusi berikut seharusnya berfungsi, karena ekspresi lambda hanya menciptakan struct anonim, yang seharusnya sesuai sebagai parameter template. Namun, banyak kesalahan yang muncul.

Contoh kode:

struct A {int x; int y;};
std::set <A, [](const A lhs, const A &rhs) ->bool {
    return lhs.x < rhs.x;
    } > SetOfA;

Keluaran kesalahan (Saya menggunakan kompiler g + + 4.5.14 dan --std = c + + 0x kompilasi):

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

Apakah itu perilaku yang diharapkan atau bug di GCC?

EDIT

Seperti yang dikatakan seseorang, saya menggunakan ekspresi lambda yang salah saat mengembalikannya contoh dari struct anonim yang mereka maksud.

Namun, memperbaiki kesalahan itu tidak memecahkan masalah. saya mendapat lambda-expression in unevaluated context kesalahan untuk kode berikut:

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;

32
2017-09-28 07:24


asal


Jawaban:


Parameter template ke-2 dari std::set mengharapkan a mengetik, bukan sebuah ekspresi, jadi hanya Anda menggunakannya dengan salah.

Anda dapat membuat set seperti ini:

auto comp = [](const A& lhs, const A& rhs) -> bool { return lhs.x < rhs.x; };
auto SetOfA = std::set <A, decltype(comp)> (comp);

33
2017-09-28 07:39



Untuk pembanding yang digunakan dengan cara ini, Anda masih lebih baik dengan pendekatan non-0x:

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;

Namun, dalam 0x Anda dapat membuat cmp_by_x tipe lokal (yaitu mendefinisikannya di dalam fungsi) ketika itu lebih nyaman, yang dilarang oleh C ++ saat ini.

Juga, perbandingan Anda memperlakukan A (x = 1, y = 1) dan A (x = 1, y = 2) sebagai ekuivalen. Jika itu tidak diinginkan, Anda perlu memasukkan nilai-nilai lain yang berkontribusi pada keunikan:

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);
  }
};

4
2017-09-30 00:19



Tidak yakin apakah ini yang Anda tanyakan, tetapi tanda tangan lambda yang mengembalikan RetType dan menerima InType akan menjadi:

std::function<RetType(InType)>

(Pastikan untuk melakukannya #include <functional>)

Anda dapat mempersingkatnya dengan menggunakan typedef, tetapi saya tidak yakin Anda dapat menggunakan decltype untuk menghindari mencari tipe yang sebenarnya (karena lambdas tampaknya tidak dapat digunakan dalam konteks itu.)

Jadi typedef Anda seharusnya:

typedef std::function<bool(const A &lhs, const A &rhs)> Comp

atau

using Comp = std::function<bool(const A &lhs, const A &rhs)>;

1
2017-09-29 13:29



masalahnya adalah parameter template terakhir adalah tipe bukan objek, jadi Anda mungkin ingin melakukan yang berikut ini

    std::set <A, std::fuction<bool(const A &,const A &)>> 
              SetOfA([](const A lhs, const A &rhs) ->bool {
                                                             return lhs.x < rhs.x;
                                                          } > SetOfA;

untuk membuatnya lebih sederhana, Anda dapat melakukan hal berikut:

auto func = SetOfA([](const A lhs, const A &rhs) ->bool { return lhs.x < rhs.x;}
set <A,decltype(func)> SetOfA(func);

tepuk tangan


0
2017-12-25 14:23