[]<typename... Types>(Types&&... args) {
foo(std::forward<Types>(args)...);
};
[] (auto&&... args) {
foo(std::forward<decltype(args)>(args)...);
};
std::visit([]<typename T>(const T& val) { // since C++20
if constexpr(std::is_same_v<T, std::string>) {
... // string-specific processing
}
std::cout << "value: " << val << '\n';
}, var);
std::visit([](const auto& val) {
if constexpr(std::is_same_v<decltype(val), const std::string&>) {
... // string-specific processing
}
std::cout << val << '\n';
}, var);
Since C++20, you can just write the following:
std::visit([]<typename T>(const T& val) { // since C++20
if constexpr(std::is_same_v<T, std::string>) {
... // string-specific processing
}
std::cout << "value: " << val << '\n';
}, var);
auto primeNumbers = [] <int Num> () {
std::array<int, Num> primes{};
... // compute and assign first Num prime numbers
return primes;
};
class NameChosenByCompiler {
public:
...
template<int Num>
auto operator() () const {
std::array<int, Num> primes{};
... // compute and assign first Num prime numbers
return primes;
}
};
// initialize array with the first 20 prime numbers:
auto primes20 = primeNumbers.operator()<20>();
auto primeNumbers = [] <int Num> (std::integral_constant<int, Num>) {
std::array<int, Num> primes{};
... // compute and assign first Num prime numbers
return primes;
};
auto primes20 = primeNumbers(std::integral_constant<int,20>{});
template<int Num>
auto primeNumbers = [] () {
std::array<int, Num> primes{};
... // compute and assign first Num prime numbers
return primes;
};
// initialize array with the first 20 prime numbers:
auto primes20 = primeNumbers<20>();
Before C++20; pass lambda has to be done through lambda's copy constructor:
In C++20; lambda default destructor is defined with no-capture lambda:
Or:
Lambdas as Non-Type Template Parameters
consteval Lambdas
Capturing this and *this
Since C++20, we have the following changes:
auto lessName = [] (const Customer& c1, const Customer& c2) {
return c1.getName() < c2.getName();
};
std::set<Customer, decltype(lessName)> coll1{lessName};
// create hash table with user-defined hash function:
auto hashName = [] (const Customer& c) {
return std::hash<std::string>{}(c.getName());
};
std::unordered_set<Customer, decltype(hashName)> coll2{0, hashName};
// create balanced binary tree with user-defined ordering criterion:
auto lessName = [] (const Customer& c1, const Customer& c2) {
return c1.getName() < c2.getName();
};
std::set<Customer, decltype(lessName)> coll1; // OK since C++20
// create balanced binary tree with user-defined ordering criterion:
std::set<Customer,
decltype([] (const Customer& c1, const Customer& c2) {
return c1.getName() < c2.getName();
})> coll3; // OK since C++20
template<std::invocable auto GetVat>
int addTax(int value)
{
return static_cast<int>(std::round(value * (1 + GetVat())));
}
auto defaultTax = [] { // OK
return 0.19;
};
std::cout << addTax<defaultTax>(100) << '\n';
auto hashed = [] (const char* str) consteval {
...
};
auto hashWine = hashed("wine"); // hash() called at compile time
const char* s = "beer";
auto hashBeer = hashed(s); // ERROR
constexpr const char* cs = "water";
auto hashWater = hashed(cs); // OK
- [=, this] is now allowed as a lambda capture (some compilers did allow it before, although it was formally invalid).
- The implicit capture of *this is deprecated.
class MyType {
std::string name;
void foo() {
int val = 0;
auto l0 = [val] { bar(val, name); }; // ERROR: member name not captured
auto l1 = [val, name=name] { bar(val, name); }; // OK, capture val and name by value
auto l2 = [&] { bar(val, name); }; // deprecated (val and name by ref.)
auto l3 = [&, this] { bar(val, name); }; // OK (val and name by reference)
auto l4 = [&, *this] { bar(val, name); }; // OK (val by reference, name by value)
auto l5 = [=] { bar(val, name); }; // deprecated (val by value, name by ref.)
auto l6 = [=, this] { bar(val, name); }; // OK (val by value, name by reference)
auto l7 = [=, *this] { bar(val, name); }; // OK (val and name by value)
}
};
std::map<int, std::string> mymap;
for (const auto& [key,val] : mymap) {
auto l = [key, val] { // OK since C++20
};
}
template<typename... Args>
void foo(Args... args)
{
auto l4 = [...args = std::move(args)] { // OK since C++20
bar(args...); // OK
};
}
template<typename... Args>
void foo(Args... args)
{
auto l4 = [&...fooArgs = args] { // OK since C++20
bar(fooArgs...); // OK
};
}
template<typename Callable, typename... Args>
auto createToCall(Callable op, Args... args)
{
return [op, ...args = std::move(args)] () -> decltype(auto) {
return op(args...);
};
}
auto createToCall(auto op, auto... args)
{
return [op, ...args = std::move(args)] () -> decltype(auto) {
return op(args...);
};
}
However, note that in this case, the
lambdas should not capture anything,
because a coroutine may easily be used longer than the lambda object,
which is created locally, exists.
No comments:
Post a Comment
Note: Only a member of this blog may post a comment.