cpp-modern-features
- Repo stars 7
- License Apache-2.0
- Author updated Live
- Author repo llamarn
- Domain
- Other
- Compatible agents
-
- Claude Code
- Cursor
- Cline
- Codex
- Windsurf
- Gemini CLI
- +20
- Trust score
- 94 / 100 · audit passed
- Author / version / license
- @DarkSorrow · Apache-2.0
- Token usage
- Lean
- Setup complexity
- Guided setup
- External API key
- Not required
- Operating systems
- Unspecified (assume cross-platform)
- Runtime requirements
- No special requirements
- Permissions
-
- Read-only
- Write / modify
- Network behavior
- Local-only
- Install commands
- 26 variants
Profile is derived at build time from SKILL.md and install vectors. Subject to drift from author intent.
Heads up: 未限定 allowed-tools,默认拥有全部工具权限。
---
name: cpp-modern-features
description: Use when modern C++ features from C++11/14/17/20 including auto, lambdas, range-based loops, str…
category: other
runtime: no special runtime
---
# cpp-modern-features output preview
## PART A: Task fit
- Use case: Use when modern C++ features from C++11/14/17/20 including auto, lambdas, range-based loops, structured bindings, and concepts. Modern C++ (C++11 and beyond) introduced significant improvements that make C++ more expressive, safer, and easier to use. This skill covers essential runs entirely locally. Works with Claude Code, Cursor, Cline and 23 more..
- Inputs: target material, constraints, expected output, and acceptance criteria.
- Evidence boundary: follow “Auto Type Inference / Lambda Expressions / Range-Based For Loops” and do not present inference as author intent.
## PART B: Execution result
- **01** The card summarizes the use case; runtime output centers on “Use when modern C++ features from C++11/14/17/20 including auto, lambdas, range-based loops, structured bindings, and concepts. Modern C++ (C++11 and beyond) introduced significant improvements that make C++ more expressive, safer, and easier to use. This skill covers essential runs entirely locally. Works with Claude Code, Cursor, Cline and 23 more.”.
- **02** When the source has headings, the agent prioritizes “Auto Type Inference / Lambda Expressions / Range-Based For Loops” so the result follows the author’s structure.
- **03** Typical output includes task judgment, concrete steps, required commands or file edits, validation, and follow-up options.
- **04** Risk context follows the fingerprint: read files, write/modify files; mostly runs locally; usually needs no extra API key.
## Running Rules
- read files, write/modify files; mostly runs locally; usually needs no extra API key.
- Validate with a small sample before expanding scope.
- Return the result, validation criteria, and next iteration options. The source does not require a stable slash command. After installation, invoke the skill by name and describe the task.
Name target files or source material, expected output, forbidden changes, and whether network or shell access is allowed. Permission fingerprint: read files, write/modify files.
Start with a small task and check whether the result follows “Auto Type Inference / Lambda Expressions / Range-Based For Loops”. Inspect diffs, logs, previews, or tests before expanding scope.
Confirm the final output includes a concrete result, evidence, and next action. If it stays generic, tighten inputs, boundaries, and acceptance criteria.
---
name: cpp-modern-features
description: Use when modern C++ features from C++11/14/17/20 including auto, lambdas, range-based loops, str…
category: other
source: DarkSorrow/llamarn
---
# cpp-modern-features
## When to use
- Use when modern C++ features from C++11/14/17/20 including auto, lambdas, range-based loops, structured bindings, and…
- Use it when the task has clear inputs, repeatable steps, and validation criteria.
## What to provide
- Target material, scope, expected result, and forbidden changes.
- Whether network, commands, file writes, or external services are allowed.
## Execution rules
- Organize steps around “Auto Type Inference / Lambda Expressions / Range-Based For Loops” and keep inference separate from source facts.
- read files, write/modify files; mostly runs locally; usually needs no extra API key.
- Validate with a small sample before expanding the task.
## Output requirements
- Return the deliverable, key evidence, validation method, and next action.
- Mark missing information as unknown; do not invent commands, platforms, or dependencies. The author source anchors workflow facts; repository files anchor sources and commands; Fluxly only adds fit, limitations, and quality judgment.
skill "cpp-modern-features" {
input -> user goal + target files + boundaries + acceptance criteria
context -> Auto Type Inference / Lambda Expressions / Range-Based For Loops
rules -> SKILL.md triggers / order / output contract
runtime -> no special runtime | read files, write/modify files | mostly runs locally
guardrails -> usually needs no extra API key + small-sample validation + diff/log review
output -> copyable result + checklist + next iteration
} Modern C++ Features
Modern C++ (C++11 and beyond) introduced significant improvements that make C++ more expressive, safer, and easier to use. This skill covers essential modern features including type inference, lambda expressions, range-based loops, smart initialization, and the latest C++20 additions.
Auto Type Inference
The auto keyword enables automatic type deduction, reducing verbosity while
maintaining type safety.
#include <iostream>
#include <vector>
#include <map>
#include <string>
void auto_examples() {
// Simple type inference
auto x = 42; // int
auto pi = 3.14159; // double
auto name = "Alice"; // const char*
auto message = std::string("Hello"); // std::string
// Iterator simplification
std::vector<int> numbers = {1, 2, 3, 4, 5};
// Before C++11
for (std::vector<int>::iterator it = numbers.begin();
it != numbers.end(); ++it) {
std::cout << *it << " ";
}
// With auto
for (auto it = numbers.begin(); it != numbers.end(); ++it) {
std::cout << *it << " ";
}
// Complex types
std::map<std::string, std::vector<int>> data;
auto it = data.find("key"); // Much cleaner than full type
// Return type deduction (C++14)
auto multiply = [](int a, int b) { return a * b; };
// Structured bindings (C++17)
std::map<std::string, int> scores = {{"Alice", 95}, {"Bob", 87}};
for (const auto& [name, score] : scores) {
std::cout << name << ": " << score << "\n";
}
}
Lambda Expressions
Lambdas provide inline anonymous functions, essential for modern C++ algorithms and callbacks.
#include <algorithm>
#include <vector>
#include <functional>
#include <iostream>
void lambda_examples() {
std::vector<int> numbers = {5, 2, 8, 1, 9, 3};
// Basic lambda
auto print = [](int n) { std::cout << n << " "; };
std::for_each(numbers.begin(), numbers.end(), print);
// Lambda with capture
int threshold = 5;
auto above_threshold = [threshold](int n) { return n > threshold; };
// Capture by value [=]
auto sum_above = [=]() {
int sum = 0;
for (int n : numbers) {
if (n > threshold) sum += n;
}
return sum;
};
// Capture by reference [&]
int count = 0;
auto count_above = [&count, threshold](int n) {
if (n > threshold) count++;
};
std::for_each(numbers.begin(), numbers.end(), count_above);
// Generic lambda (C++14)
auto generic_print = [](const auto& item) {
std::cout << item << " ";
};
// Lambda as comparator
std::sort(numbers.begin(), numbers.end(),
[](int a, int b) { return a > b; }); // Descending
// Mutable lambda
auto counter = [count = 0]() mutable {
return ++count;
};
std::cout << counter() << "\n"; // 1
std::cout << counter() << "\n"; // 2
}
// Returning lambdas
std::function<int(int)> make_multiplier(int factor) {
return [factor](int n) { return n * factor; };
}
Range-Based For Loops
Range-based for loops provide clean, safe iteration over containers and ranges.
#include <vector>
#include <map>
#include <string>
#include <iostream>
void range_based_loops() {
std::vector<int> numbers = {1, 2, 3, 4, 5};
// Basic iteration
for (int n : numbers) {
std::cout << n << " ";
}
// By reference (for modification)
for (int& n : numbers) {
n *= 2;
}
// By const reference (efficient for large objects)
std::vector<std::string> names = {"Alice", "Bob", "Charlie"};
for (const auto& name : names) {
std::cout << name << "\n";
}
// With structured bindings (C++17)
std::map<std::string, int> ages = {
{"Alice", 30},
{"Bob", 25},
{"Charlie", 35}
};
for (const auto& [name, age] : ages) {
std::cout << name << " is " << age << " years old\n";
}
// Initializer in for loop (C++20)
for (std::vector<int> temp = {1, 2, 3}; auto n : temp) {
std::cout << n << " ";
}
}
// Custom range support
class Range {
int start_, end_;
public:
Range(int start, int end) : start_(start), end_(end) {}
struct Iterator {
int current;
Iterator(int val) : current(val) {}
int operator*() const { return current; }
Iterator& operator++() { ++current; return *this; }
bool operator!=(const Iterator& other) const {
return current != other.current;
}
};
Iterator begin() const { return Iterator(start_); }
Iterator end() const { return Iterator(end_); }
};
void use_custom_range() {
for (int i : Range(0, 10)) {
std::cout << i << " ";
}
}
Uniform Initialization
Uniform initialization using braces provides consistent syntax and prevents narrowing conversions.
#include <vector>
#include <string>
#include <map>
struct Point {
int x, y;
};
void uniform_initialization() {
// Built-in types
int a{42};
double pi{3.14159};
// Containers
std::vector<int> numbers{1, 2, 3, 4, 5};
std::map<std::string, int> ages{
{"Alice", 30},
{"Bob", 25}
};
// Aggregates
Point p{10, 20};
// Prevents narrowing
// int x{3.14}; // Compiler error!
int x = 3.14; // Compiles (implicit conversion)
// Empty initialization (zero/default)
int zero{}; // 0
std::string empty{}; // ""
// Return value
auto get_numbers = []() { return std::vector<int>{1, 2, 3}; };
}
// Most vexing parse solution
class Widget {
public:
Widget() = default;
Widget(int x) {}
};
void vexing_parse() {
// Before C++11: declares a function!
// Widget w();
// Modern C++: creates an object
Widget w{}; // Correct
Widget w2{10}; // Also correct
}
Move Semantics and Rvalue References
Move semantics enable efficient transfer of resources without copying, crucial for performance.
#include <vector>
#include <string>
#include <utility>
#include <iostream>
class Buffer {
size_t size_;
int* data_;
public:
// Constructor
Buffer(size_t size) : size_(size), data_(new int[size]) {
std::cout << "Constructor\n";
}
// Copy constructor
Buffer(const Buffer& other)
: size_(other.size_), data_(new int[other.size_]) {
std::copy(other.data_, other.data_ + size_, data_);
std::cout << "Copy constructor\n";
}
// Move constructor
Buffer(Buffer&& other) noexcept
: size_(other.size_), data_(other.data_) {
other.size_ = 0;
other.data_ = nullptr;
std::cout << "Move constructor\n";
}
// Copy assignment
Buffer& operator=(const Buffer& other) {
if (this != &other) {
delete[] data_;
size_ = other.size_;
data_ = new int[size_];
std::copy(other.data_, other.data_ + size_, data_);
std::cout << "Copy assignment\n";
}
return *this;
}
// Move assignment
Buffer& operator=(Buffer&& other) noexcept {
if (this != &other) {
delete[] data_;
size_ = other.size_;
data_ = other.data_;
other.size_ = 0;
other.data_ = nullptr;
std::cout << "Move assignment\n";
}
return *this;
}
~Buffer() { delete[] data_; }
};
void move_semantics_example() {
Buffer b1(100);
Buffer b2 = std::move(b1); // Move, not copy
std::vector<Buffer> buffers;
buffers.push_back(Buffer(50)); // Move constructor used
// Perfect forwarding
auto make_buffer = [](auto&&... args) {
return Buffer(std::forward<decltype(args)>(args)...);
};
}
Variadic Templates
Variadic templates enable functions and classes that accept any number of arguments.
#include <iostream>
#include <string>
// Base case
void print() {
std::cout << "\n";
}
// Recursive variadic template
template<typename T, typename... Args>
void print(T first, Args... rest) {
std::cout << first << " ";
print(rest...);
}
// Fold expressions (C++17)
template<typename... Args>
auto sum(Args... args) {
return (args + ...);
}
template<typename... Args>
auto sum_with_init(Args... args) {
return (args + ... + 0);
}
// Perfect forwarding with variadic templates
template<typename T, typename... Args>
std::unique_ptr<T> make_unique_custom(Args&&... args) {
return std::unique_ptr<T>(new T(std::forward<Args>(args)...));
}
void variadic_examples() {
print(1, 2.5, "hello", std::string("world"));
auto total = sum(1, 2, 3, 4, 5); // 15
// Fold expressions for various operations
auto all_true = [](auto... args) {
return (args && ...);
};
auto any_true = [](auto... args) {
return (args || ...);
};
}
Structured Bindings (C++17)
Structured bindings decompose objects into their constituent parts, improving code readability.
#include <tuple>
#include <map>
#include <string>
#include <array>
struct Person {
std::string name;
int age;
double salary;
};
std::tuple<int, std::string, double> get_employee() {
return {42, "Alice", 75000.0};
}
void structured_bindings() {
// Tuple decomposition
auto [id, name, salary] = get_employee();
// Pair decomposition
std::pair<int, std::string> p{1, "one"};
auto [num, text] = p;
// Struct decomposition
Person person{"Bob", 30, 80000.0};
auto [pname, page, psalary] = person;
// Array decomposition
std::array<int, 3> arr{1, 2, 3};
auto [a, b, c] = arr;
// Map iteration
std::map<std::string, int> scores{{"Alice", 95}, {"Bob", 87}};
for (const auto& [name, score] : scores) {
std::cout << name << ": " << score << "\n";
}
// References
auto& [rname, rage, rsalary] = person;
rage = 31; // Modifies person.age
}
Concepts (C++20)
Concepts constrain template parameters, providing better error messages and clearer interfaces.
#include <concepts>
#include <iostream>
#include <vector>
// Define custom concept
template<typename T>
concept Numeric = std::integral<T> || std::floating_point<T>;
// Use concept to constrain template
template<Numeric T>
T add(T a, T b) {
return a + b;
}
// Concept with multiple constraints
template<typename T>
concept Printable = requires(T t) {
{ std::cout << t } -> std::convertible_to<std::ostream&>;
};
template<Printable T>
void print(const T& value) {
std::cout << value << "\n";
}
// Range concept
template<typename T>
concept Range = requires(T r) {
r.begin();
r.end();
};
template<Range R>
void print_range(const R& range) {
for (const auto& item : range) {
std::cout << item << " ";
}
std::cout << "\n";
}
// Concept with associated types
template<typename T>
concept Container = requires(T c) {
typename T::value_type;
typename T::iterator;
{ c.begin() } -> std::same_as<typename T::iterator>;
{ c.end() } -> std::same_as<typename T::iterator>;
{ c.size() } -> std::convertible_to<std::size_t>;
};
template<Container C>
void process_container(const C& container) {
std::cout << "Size: " << container.size() << "\n";
}
void concepts_example() {
auto result = add(5, 10); // OK
auto dresult = add(5.5, 2.3); // OK
// auto sresult = add("hi", "there"); // Error: doesn't satisfy
// Numeric
print(42);
print("Hello");
std::vector<int> vec{1, 2, 3};
print_range(vec);
process_container(vec);
}
Ranges Library (C++20)
The ranges library provides composable algorithms and views for working with sequences.
#include <ranges>
#include <vector>
#include <iostream>
#include <algorithm>
void ranges_examples() {
std::vector<int> numbers{1, 2, 3, 4, 5, 6, 7, 8, 9, 10};
// Views are lazy and composable
auto even = [](int n) { return n % 2 == 0; };
auto square = [](int n) { return n * n; };
// Compose operations without intermediate containers
auto result = numbers
| std::views::filter(even)
| std::views::transform(square)
| std::views::take(3);
for (int n : result) {
std::cout << n << " "; // 4 16 36
}
std::cout << "\n";
// Range algorithms
std::ranges::sort(numbers, std::greater{});
// Find with projection
struct Person {
std::string name;
int age;
};
std::vector<Person> people{
{"Alice", 30},
{"Bob", 25},
{"Charlie", 35}
};
auto it = std::ranges::find(people, "Bob", &Person::name);
// Views::iota for number generation
for (int i : std::views::iota(1, 6)) {
std::cout << i << " "; // 1 2 3 4 5
}
std::cout << "\n";
// Split view
std::string text = "one,two,three";
for (auto word : text | std::views::split(',')) {
for (char c : word) {
std::cout << c;
}
std::cout << " ";
}
}
Best Practices
- Use
autofor complex types and iterators but keep simple types explicit - Prefer lambdas over function objects for inline operations and callbacks
- Use range-based for loops instead of manual iterator manipulation
- Initialize variables with
{}to prevent narrowing conversions - Implement move constructors and assignments for resource-owning classes
- Use
std::movewhen transferring ownership, not for general optimization - Prefer structured bindings over
std::get<>()for tuples and pairs - Use concepts to constrain templates and improve error messages
- Leverage ranges for composable, lazy operations on sequences
- Use
const auto&for range-based loops with large objects
Common Pitfalls
- Overusing
automaking code less readable when types provide clarity - Capturing by reference in lambdas that outlive their captures
- Using
std::moveon const objects, which disables move semantics - Forgetting
noexcepton move operations, preventing optimizations - Modifying containers while iterating with range-based for loops
- Dangling references from structured bindings of temporary objects
- Using fold expressions without considering operator precedence
- Assuming ranges views create copies instead of providing lazy views
- Moving from objects that will be used again later
- Not marking move constructors and assignments as
noexcept
When to Use Modern C++ Features
Use modern C++ features when you need:
- Cleaner, more expressive code with less boilerplate
- Better type safety with concepts and structured bindings
- Improved performance through move semantics
- Functional programming patterns with lambdas and ranges
- Generic programming with less template complexity
- Safer resource management with smart pointers
- Code that's easier to maintain and refactor
- Better compiler error messages with concepts
- Lazy evaluation and composition with ranges
- Migration from older C++ codebases to modern standards
Decide Fit First
Design Intent
How To Use It
Boundaries And Review