Вызов лямбды с непараметрическим аргументом шаблона

#c #templates #lambda #c 20

Вопрос:

MSVC 2019 позволяет мне определить лямбду, подобную этой, где аргумент шаблона не используется в списке параметров:

 auto foo = []<bool B>() {
  return B;
};
 

Однако это приводит к синтаксической ошибке при попытке вызвать его таким образом?

 foo<false>();
 

Как правильно вызывать лямбду с аргументом шаблона, не являющимся параметром?

Комментарии:

1. foo.operator()<false>();

Ответ №1:

Параметр шаблона используется с operator() параметром лямбда.

(начиная с C 20) Если в определении лямбда используется явный список параметров шаблона, этот список параметров шаблона используется с оператором().

Вы можете указать аргумент шаблона , не относящийся к типу, для operator() вызова лямбды в ненормальном стиле, как:

 foo.operator()<false>();
 

Ответ №2:

foo является объектом функции. У него есть operator() . Шаблон лямбда-выражения находится на этом операторе, а не на самом имени объекта.

foo<T> пытается указать имя foo в качестве аргумента шаблона T ; здесь это недопустимо. foo<T>() задает аргумент шаблона foo , затем вызывает () результат. Опять же, не то, что здесь происходит.

Переменная шаблона будет работать так, как вы этого хотите:

 template<bool B>
auto foo = []() {
  return B;
};
 

такие переменные работают только в глобальной области, но здесь foo<true>() это сработало бы.

Поскольку лямбда-код на самом деле является классом, генерируемым компилятором:

 struct some_secret_name {
  template<bool B>
  auto operator()() const {
    return B;
  }
};
some_secret_name foo;
 

тогда «правильный» способ назвать это уродливым синтаксисом:

 foo.operator()<true>();
 

это, честно говоря, отстой.

Вы можете получить немного лучший синтаксис, как это:

 template<class T> struct tag_t {using type=T;};
template<class T> constexpr tag_t<T> tag_v={};
template<auto v> using value_t = std::integral_constant<std::decay_t<decltype(v)>, v>;
template<auto v> constexpr value_t<v> value_v={};
 

тогда мы сможем сделать

 auto foo = []<bool B>(value_t<B>) {
  return []{
    return B;
  };
};
 

теперь синтаксис таков:

 foo(value_v<false>)();
 

что выглядит немного менее неуклюже, хотя и чересчур волшебно.

foo теперь это лямбда, которая создает лямбды, внешняя лямбда принимает параметры вашего шаблона в качестве аргументов функции, а внутренняя лямбда-это тело.