| doc_id | NET-API-003 |
|---|---|
| doc_title | C++20 Concepts for Network System |
| doc_version | 1.0.0 |
| doc_date | 2026-04-04 |
| doc_status | Released |
| project | network_system |
| category | API |
SSOT: This document is the single source of truth for C++20 Concepts for Network System.
Version: 0.1.0 Last Updated: 2025-12-10 Status: Complete
This guide provides comprehensive documentation for the C++20 Concepts feature in network_system.
- Overview
- Why Concepts?
- Compiler Requirements
- Header Files
- Concept Reference
- Usage Patterns
- Integration with common_system
- Best Practices
- Examples
network_system provides 16 C++20 concepts for compile-time validation of network-related types. These concepts improve code quality through:
- Better error messages: Clear compile-time errors instead of cryptic template failures
- Self-documenting code: Concepts express interface requirements explicitly
- Type safety: Catch type mismatches at compile time, not runtime
#include <kcenon/network/concepts/concepts.h>
// Using a concept to constrain a template parameter
template<network_system::concepts::DataReceiveHandler Handler>
void set_receive_callback(Handler&& handler) {
// Compile-time guaranteed: handler accepts const std::vector<uint8_t>&
receive_handler_ = std::forward<Handler>(handler);
}
// The compiler will reject invalid handlers with clear error messages
set_receive_callback([](const std::vector<uint8_t>& data) {
// Process data...
});// Hard to read, cryptic error messages
template<typename F,
typename = std::enable_if_t<
std::is_invocable_v<F, const std::vector<uint8_t>&>>>
void set_handler(F&& handler);Error message without concepts:
error: no matching function for call to 'set_handler'
note: candidate template ignored: substitution failure [with F = int]:
no type named 'type' in 'std::enable_if<false, void>'
// Clear and readable
template<DataReceiveHandler Handler>
void set_handler(Handler&& handler);Error message with concepts:
error: constraints not satisfied for template 'set_handler'
note: because 'int' does not satisfy 'DataReceiveHandler'
note: because 'std::invocable<int, const std::vector<uint8_t>&>' evaluated to false
| Compiler | Minimum Version | Recommended |
|---|---|---|
| GCC | 10+ | 11+ |
| Clang | 10+ | 14+ |
| MSVC | 2022 (19.29+) | 2022 |
| Apple Clang | 13+ | 14+ |
Concepts require C++20 standard. Enable with:
set(CMAKE_CXX_STANDARD 20)
set(CMAKE_CXX_STANDARD_REQUIRED ON)| Header | Purpose |
|---|---|
<kcenon/network/concepts/concepts.h> |
Unified umbrella header (recommended) |
<kcenon/network/concepts/network_concepts.h> |
All 16 concept definitions |
| Header | Purpose |
|---|---|
<network_system/concepts/concepts.h> |
Legacy namespace support |
<network_system/concepts/network_concepts.h> |
Legacy namespace support |
// Recommended: Use the umbrella header
#include <kcenon/network/concepts/concepts.h>
// Or directly include network concepts
#include <kcenon/network/concepts/network_concepts.h>
// Concepts are in the network_system::concepts namespace
using namespace network_system::concepts;A type that can serve as a network data buffer with read-only access.
template <typename T>
concept ByteBuffer = requires(const T t) {
{ t.data() } -> std::convertible_to<const void*>;
{ t.size() } -> std::convertible_to<std::size_t>;
};Requirements:
data(): Returns pointer to byte datasize(): Returns number of bytes
Satisfied by:
std::vector<uint8_t>std::stringstd::array<uint8_t, N>std::span<const uint8_t>
Example:
template<ByteBuffer Buffer>
void send_data(const Buffer& buffer) {
const void* ptr = buffer.data();
std::size_t len = buffer.size();
// Send ptr with len bytes...
}
// Usage
std::vector<uint8_t> data = {1, 2, 3, 4};
send_data(data); // OK
std::string str = "hello";
send_data(str); // OK
int x = 42;
send_data(x); // Compile error: 'int' does not satisfy 'ByteBuffer'A mutable byte buffer that can be resized, extending ByteBuffer.
template <typename T>
concept MutableByteBuffer = ByteBuffer<T> && requires(T t, std::size_t n) {
{ t.resize(n) };
{ t.data() } -> std::convertible_to<void*>;
};Requirements:
- All
ByteBufferrequirements resize(n): Resize buffer to n bytesdata(): Returns mutable pointer
Satisfied by:
std::vector<uint8_t>std::string
Example:
template<MutableByteBuffer Buffer>
void receive_data(Buffer& buffer, std::size_t expected_size) {
buffer.resize(expected_size);
void* ptr = buffer.data();
// Fill buffer with received data...
}
// Usage
std::vector<uint8_t> buffer;
receive_data(buffer, 1024); // OK
std::array<uint8_t, 100> arr;
receive_data(arr, 50); // Compile error: no resize() methodA callback type for handling received data.
template <typename F>
concept DataReceiveHandler = std::invocable<F, const std::vector<uint8_t>&>;Signature: void(const std::vector<uint8_t>&)
Example:
template<DataReceiveHandler Handler>
void set_receive_handler(Handler&& handler) {
receive_handler_ = std::forward<Handler>(handler);
}
// Valid handlers
set_receive_handler([](const std::vector<uint8_t>& data) {
std::cout << "Received " << data.size() << " bytes\n";
});
void my_handler(const std::vector<uint8_t>& data);
set_receive_handler(my_handler);
struct MyHandler {
void operator()(const std::vector<uint8_t>& data) { /* ... */ }
};
set_receive_handler(MyHandler{});A callback type for handling network errors.
template <typename F>
concept ErrorHandler = std::invocable<F, std::error_code>;Signature: void(std::error_code)
Example:
template<ErrorHandler Handler>
void set_error_handler(Handler&& handler) {
error_handler_ = std::forward<Handler>(handler);
}
set_error_handler([](std::error_code ec) {
std::cerr << "Error: " << ec.message() << "\n";
});A callback type for handling connection state changes.
template <typename F>
concept ConnectionHandler = std::invocable<F>;Signature: void()
Example:
template<ConnectionHandler Handler>
void set_connected_handler(Handler&& handler) {
on_connected_ = std::forward<Handler>(handler);
}
set_connected_handler([]() {
std::cout << "Connected!\n";
});A callback type for handling session events with a session pointer.
template <typename F, typename Session>
concept SessionHandler = std::invocable<F, std::shared_ptr<Session>>;Signature: void(std::shared_ptr<Session>)
Example:
template<typename Session, SessionHandler<Session> Handler>
void set_session_handler(Handler&& handler) {
session_handler_ = std::forward<Handler>(handler);
}
set_session_handler([](std::shared_ptr<MySession> session) {
std::cout << "Session: " << session->get_session_id() << "\n";
});A callback type for handling data received on a specific session.
template <typename F, typename Session>
concept SessionDataHandler =
std::invocable<F, std::shared_ptr<Session>, const std::vector<uint8_t>&>;Signature: void(std::shared_ptr<Session>, const std::vector<uint8_t>&)
A callback type for handling errors on a specific session.
template <typename F, typename Session>
concept SessionErrorHandler =
std::invocable<F, std::shared_ptr<Session>, std::error_code>;Signature: void(std::shared_ptr<Session>, std::error_code)
A callback type for handling disconnection events with session ID.
template <typename F>
concept DisconnectionHandler = std::invocable<F, const std::string&>;Signature: void(const std::string&) (session ID)
Example:
template<DisconnectionHandler Handler>
void set_disconnect_handler(Handler&& handler) {
on_disconnect_ = std::forward<Handler>(handler);
}
set_disconnect_handler([](const std::string& session_id) {
std::cout << "Disconnected: " << session_id << "\n";
});A callback type for reconnection attempt notifications.
template <typename F>
concept RetryCallback = std::invocable<F, std::size_t>;Signature: void(std::size_t) (attempt number)
Example:
template<RetryCallback Handler>
void set_retry_handler(Handler&& handler) {
on_retry_ = std::forward<Handler>(handler);
}
set_retry_handler([](std::size_t attempt) {
std::cout << "Retry attempt: " << attempt << "\n";
});A type that satisfies basic network client requirements.
template <typename T>
concept NetworkClient = requires(T t, std::vector<uint8_t> data) {
{ t.is_connected() } -> std::convertible_to<bool>;
{ t.send_packet(std::move(data)) };
{ t.stop_client() };
};Requirements:
is_connected(): Returns connection statussend_packet(data): Sends data packetstop_client(): Stops the client
Example:
template<NetworkClient Client>
void use_client(Client& client, const std::string& message) {
if (client.is_connected()) {
std::vector<uint8_t> data(message.begin(), message.end());
client.send_packet(std::move(data));
}
}
// Works with messaging_client
network_system::core::messaging_client client("MyClient");
use_client(client, "Hello!");A type that satisfies basic network server requirements.
template <typename T>
concept NetworkServer = requires(T t, unsigned short port) {
{ t.start_server(port) };
{ t.stop_server() };
};Requirements:
start_server(port): Starts listening on portstop_server(): Stops the server
Example:
template<NetworkServer Server>
void manage_server(Server& server, unsigned short port) {
server.start_server(port);
// ... run server ...
server.stop_server();
}A type that represents a network session.
template <typename T>
concept NetworkSession = requires(T t) {
{ t.get_session_id() } -> std::convertible_to<std::string>;
{ t.start_session() };
{ t.stop_session() };
};Requirements:
get_session_id(): Returns unique session identifierstart_session(): Starts the sessionstop_session(): Stops the session
Example:
template<NetworkSession Session>
void handle_session(std::shared_ptr<Session> session) {
auto id = session->get_session_id();
std::cout << "Handling session: " << id << "\n";
session->start_session();
}A type that can transform data (e.g., compression, encryption).
template <typename T>
concept DataTransformer = requires(T t, std::vector<uint8_t>& data) {
{ t.transform(data) } -> std::convertible_to<bool>;
};Requirements:
transform(data): Transforms data in-place, returns success
Example:
template<DataTransformer Transformer>
bool apply_transform(Transformer& t, std::vector<uint8_t>& data) {
return t.transform(data);
}
// Custom compressor
class GzipCompressor {
public:
bool transform(std::vector<uint8_t>& data) {
// Compress data...
return true;
}
};
GzipCompressor compressor;
std::vector<uint8_t> data = { /* ... */ };
apply_transform(compressor, data); // OKA transformer that supports both forward and reverse operations.
template <typename T>
concept ReversibleDataTransformer =
DataTransformer<T> && requires(T t, std::vector<uint8_t>& data) {
{ t.reverse_transform(data) } -> std::convertible_to<bool>;
};Requirements:
- All
DataTransformerrequirements reverse_transform(data): Reverses the transformation
Example:
template<ReversibleDataTransformer Transformer>
void process_bidirectional(Transformer& t, std::vector<uint8_t>& data) {
t.transform(data); // e.g., compress
// ... transmit ...
t.reverse_transform(data); // e.g., decompress
}
class SymmetricEncryptor {
public:
bool transform(std::vector<uint8_t>& data) { /* encrypt */ return true; }
bool reverse_transform(std::vector<uint8_t>& data) { /* decrypt */ return true; }
};A type that represents a time duration (compatible with std::chrono).
template <typename T>
concept Duration = requires {
typename T::rep;
typename T::period;
} && std::is_arithmetic_v<typename T::rep>;Satisfied by:
std::chrono::secondsstd::chrono::millisecondsstd::chrono::microseconds- Any
std::chrono::durationspecialization
Example:
template<Duration D>
void set_timeout(D duration) {
auto ms = std::chrono::duration_cast<std::chrono::milliseconds>(duration);
timeout_ms_ = ms.count();
}
set_timeout(std::chrono::seconds(30)); // OK
set_timeout(std::chrono::milliseconds(500)); // OK
set_timeout(5); // Compile error: int is not Duration// Single concept constraint
template<DataReceiveHandler Handler>
void set_handler(Handler&& handler);
// Multiple concept constraints
template<typename T>
requires NetworkClient<T> && std::copy_constructible<T>
void use_client(T client);
// Abbreviated function template syntax
void process(ByteBuffer auto const& buffer);// Using conjunction
template<typename T>
requires DataTransformer<T> && std::default_initializable<T>
auto create_transformer() -> T;
// Using disjunction
template<typename T>
requires ByteBuffer<T> || std::ranges::contiguous_range<T>
void send(const T& data);// Different implementations based on concept satisfaction
template<ByteBuffer T>
void send(const T& buffer) {
send_raw(buffer.data(), buffer.size());
}
template<typename T>
requires std::ranges::range<T> && (!ByteBuffer<T>)
void send(const T& range) {
std::vector<uint8_t> buffer(std::ranges::begin(range), std::ranges::end(range));
send_raw(buffer.data(), buffer.size());
}When BUILD_WITH_COMMON_SYSTEM is enabled, additional concepts from common_system are available:
| Concept | Description |
|---|---|
Resultable<T> |
Types that produce Result |
Unwrappable<T> |
Types with unwrap() method |
Mappable<T> |
Types supporting map operations |
#include <kcenon/network/concepts/concepts.h>
// When common_system is available
#if KCENON_WITH_COMMON_SYSTEM
template<typename T>
requires common_system::concepts::Resultable<T>
void handle_result(T&& result) {
if (result.is_ok()) {
// Process success...
} else {
// Handle error...
}
}
#endif// Good: Clear and readable
template<DataReceiveHandler Handler>
void set_handler(Handler&& h);
// Avoid: Hard to read
template<typename F, typename = std::enable_if_t<...>>
void set_handler(F&& h);// Good: Describes the requirement
template<NetworkClient Client>
void use_client(Client& c);
// Avoid: Too generic
template<typename T>
void use_client(T& c);/**
* @brief Process network data with a transformer
* @tparam T Must satisfy ReversibleDataTransformer concept
* @param transformer The data transformer to apply
* @param data Data to transform (modified in place)
*/
template<ReversibleDataTransformer T>
void process(T& transformer, std::vector<uint8_t>& data);Use static_assert for additional context:
template<typename Handler>
void set_handler(Handler&& h) {
static_assert(DataReceiveHandler<Handler>,
"Handler must be callable with const std::vector<uint8_t>&");
// ...
}#include <kcenon/network/concepts/concepts.h>
#include <functional>
#include <iostream>
#include <vector>
using namespace network_system::concepts;
class TypeSafeClient {
public:
// Constrained callback setters
template<DataReceiveHandler Handler>
void on_data(Handler&& handler) {
data_handler_ = std::forward<Handler>(handler);
}
template<ErrorHandler Handler>
void on_error(Handler&& handler) {
error_handler_ = std::forward<Handler>(handler);
}
template<ConnectionHandler Handler>
void on_connect(Handler&& handler) {
connect_handler_ = std::forward<Handler>(handler);
}
template<RetryCallback Handler>
void on_retry(Handler&& handler) {
retry_handler_ = std::forward<Handler>(handler);
}
private:
std::function<void(const std::vector<uint8_t>&)> data_handler_;
std::function<void(std::error_code)> error_handler_;
std::function<void()> connect_handler_;
std::function<void(std::size_t)> retry_handler_;
};
int main() {
TypeSafeClient client;
// All these compile successfully
client.on_data([](const std::vector<uint8_t>& data) {
std::cout << "Received: " << data.size() << " bytes\n";
});
client.on_error([](std::error_code ec) {
std::cerr << "Error: " << ec.message() << "\n";
});
client.on_connect([]() {
std::cout << "Connected!\n";
});
client.on_retry([](std::size_t attempt) {
std::cout << "Retry #" << attempt << "\n";
});
// These would NOT compile (good!)
// client.on_data([](int x) {}); // Wrong parameter type
// client.on_error([](std::string s) {}); // Wrong parameter type
// client.on_connect([](int x) {}); // Handler shouldn't take parameters
return 0;
}#include <kcenon/network/concepts/concepts.h>
#include <memory>
#include <string>
#include <vector>
using namespace network_system::concepts;
// Generic wrapper that works with any NetworkClient
template<NetworkClient ClientType>
class ClientWrapper {
public:
explicit ClientWrapper(std::shared_ptr<ClientType> client)
: client_(std::move(client)) {}
bool send_message(const std::string& message) {
if (!client_->is_connected()) {
return false;
}
std::vector<uint8_t> data(message.begin(), message.end());
client_->send_packet(std::move(data));
return true;
}
void shutdown() {
client_->stop_client();
}
bool is_ready() const {
return client_->is_connected();
}
private:
std::shared_ptr<ClientType> client_;
};
// Usage with messaging_client
#include <kcenon/network/core/messaging_client.h>
int main() {
auto client = std::make_shared<network_system::core::messaging_client>("MyClient");
// This compiles because messaging_client satisfies NetworkClient
ClientWrapper wrapper(client);
if (wrapper.is_ready()) {
wrapper.send_message("Hello, World!");
}
wrapper.shutdown();
return 0;
}- API Reference - Complete API documentation
- Architecture - System design overview
- Integration with common_system - Common system integration
- C++ Reference: Concepts
Last Updated: 2025-12-10 Maintained by: kcenon@naver.com