C++23stlexpert
std::move_only_function (C++23 Addition)
C++23 · Completing Modern · Compiler flag: -std=c++23
Explanation
Function wrapper for move-only callables (e.g., lambdas with unique_ptr).
Real-World Scenario
Store move-only callbacks in an event queue.
Quick Snippet
snippet.cpp
#include <functional> std::move_only_function<void()> f = []{ /* action */ };Full Example
move_only_function.cpp
// CodeNebula - C++23 Example: std::move_only_function
// Compile: g++ -std=c++23 -Wall -Wextra -o example move_only_function.cpp
// Note: Requires GCC 13+ / Clang 17+
#include <functional>
#include <iostream>
#include <memory>
#include <string>
#include <vector>
// std::move_only_function is like std::function but supports non-copyable
// callables. It is itself move-only. It also has const/noexcept qualifiers
// in its signature, unlike std::function which always calls via const.
// A move-only callable: captures a unique_ptr
auto make_greeter(std::string name) {
auto msg = std::make_unique<std::string>("Hello from " + name + "!");
return [msg = std::move(msg)]() {
std::cout << *msg << "\n";
};
}
// A task queue using move_only_function
class TaskQueue {
std::vector<std::move_only_function<void()>> tasks_;
public:
void add(std::move_only_function<void()> task) {
tasks_.push_back(std::move(task));
}
void run_all() {
for (auto& task : tasks_) {
task();
}
tasks_.clear();
}
std::size_t size() const { return tasks_.size(); }
};
int main() {
std::cout << "=== std::move_only_function ===\n\n";
// Basic usage with a move-only lambda
std::move_only_function<void()> fn = make_greeter("Alice");
std::cout << "Calling move-only function:\n";
fn();
// Move to another variable (copying would fail to compile)
auto fn2 = std::move(fn);
std::cout << "\nAfter move, calling from new variable:\n";
fn2();
// Check that original is empty after move
std::cout << "Original is empty after move: "
<< (!fn ? "yes" : "no") << "\n";
// Task queue with heterogeneous move-only tasks
std::cout << "\n--- Task Queue ---\n";
TaskQueue queue;
queue.add(make_greeter("Bob"));
queue.add([counter = std::make_unique<int>(0)]() mutable {
++(*counter);
std::cout << "Counter task: " << *counter << "\n";
});
queue.add([]() {
std::cout << "Simple lambda task\n";
});
std::cout << "Queue has " << queue.size() << " tasks\n";
queue.run_all();
std::cout << "Queue has " << queue.size() << " tasks after run_all\n";
// With return value
std::move_only_function<int(int, int)> adder = [](int a, int b) {
return a + b;
};
std::cout << "\nadder(3, 4) = " << adder(3, 4) << "\n";
return 0;
}
// Expected output:
// === std::move_only_function ===
//
// Calling move-only function:
// Hello from Alice!
//
// After move, calling from new variable:
// Hello from Alice!
// Original is empty after move: yes
//
// --- Task Queue ---
// Queue has 3 tasks
// Hello from Bob!
// Counter task: 1
// Simple lambda task
// Queue has 0 tasks after run_all
//
// adder(3, 4) = 7
Run command
g++ -std=c++23 -Wall -Wextra -o example move_only_function.cpp