Лямбда-выражения как параметры шаблона класса
можно ли использовать лямбда-выражения как параметры шаблона класса? (Обратите внимание, что это совсем другой вопрос, чем этот, который спрашивает, Может ли само лямбда-выражение быть шаблонизировано.)
Я прошу, если вы можете сделать что-то вроде:
template <class Functor>
struct Foo { };
// ...
Foo<decltype([]()->void { })> foo;
Это было бы полезно в тех случаях, когда, например, шаблона класса имеет различные параметры, такие как equal_to
или что-то, что обычно реализуется как однострочные функторы. Например, предположим, что я хочу создайте экземпляр хэш-таблицы, которая использует мою собственную функцию сравнения равенства. Я хотел бы иметь возможность сказать что-то вроде:
typedef std::unordered_map<
std::string,
std::string,
std::hash<std::string>,
decltype([](const std::string& s1, const std::string& s2)->bool
{ /* Custom implementation of equal_to */ })
> map_type;
но я проверил это на GCC 4.4 и 4.6, и это не работает, по-видимому, потому, что анонимный тип, созданный лямбда-выражением, не имеет конструктора по умолчанию. (Я помню аналогичную проблему с boost::bind
.) Есть ли какая-то причина, по которой проект стандарта не позволяет этого, или я ошибаюсь, и это разрешено, но GCC просто отстает в своем реализация?
4 ответа:
Я прошу, если вы можете сделать что-то вроде:
Foo<decltype([]()->void { })> foo;
нет, вы не можете, потому что лямбда-выражения не должны появляться в необработанные контексте (например,
decltype
иsizeof
, среди других). C++0x FDIS, 5.1.2 [expr.подтянутый.лямбда] p2оценка лямбда-выражения приводит к временному значению prvalue (12.2). Это временное явление называется объект закрытия. лямбда-выражение не должно появляться в недооцененном виде операнд (п. 5). [ Примечание: объекта закрытие ведет себя как объект функции (20.8).- Конечная нота ] (выделено мной)
вам нужно будет сначала создать определенную лямбду, а затем использовать decltype на этом:
auto my_comp = [](const std::string& left, const std::string& right) -> bool { // whatever } typedef std::unordered_map< std::string, std::string, std::hash<std::string>, decltype(my_comp) > map_type;
это потому, что каждый лямбда-производный объект закрытия может иметь совершенно другой тип, они похожи аноним функции в конце концов.
@Xeo дал вам причину, так что я дам вам работу вокруг.
часто вы не хотите называть закрытие, в этом случае вы можете использовать
std::function
, тип:typedef std::unordered_map< std::string, std::string, std::hash<std::string>, std::function<bool(std::string const&, std::string const&)> > map_type;
обратите внимание, что он захватывает именно сигнатуру функции, и не более того.
затем вы можете просто написать лямбда при построении карты.
обратите внимание, что с
unordered_map
, Если вы измените сравнение равенства, вам лучше изменить хэш, чтобы соответствовать поведению. Объекты, которые сравниваются равными, должны иметь одинаковый хэш.
вы не можете сделать это с закрытием, потому что состояние не содержится в типе.
Если ваша лямбда не имеет состояния (нет захватов), то вы должны быть в порядке. В этом случае лямбда распадается на обычный указатель функции, который можно использовать в качестве аргумента шаблона вместо некоторого типа лямбда.
gcc не нравится. http://ideone.com/bHM3n