cpp-kwargs is a library that implements Python-like **kwargs
parameter passing in C++.
It encapsulates a Kwargs
class using C++'s powerful template programming to achieve this functionality.
Python's **kwargs
In Python, **Kwargs
is used in function definitions to accept any number of keyword arguments. It wraps all arguments passed as Key=Value
into a dictionary, which can be accessed via kwargs
inside the function. **kwargs
allows functions to flexibly accept a variable number of keyword arguments, enhancing code scalability. Official Documentation.
-
Python (**kwargs) and cpp-kwargs both support:
- Keys in any order;
- Missing or extra keys;
- Limited key names;
- Values of any type;
- Preserving original value types;
-
cpp-kwargs additionally supports:
- Automatic type conversion (when input and output types are mismatched);
- Smaller overhead,
Kwargs
usesconstexpr
internally as much as possible, providing results at compile time (if conditions are met); - Key names are case-insensitive (optional);
Tip
It's recommended to use C++ STL
in C++ constexpr
, and code writing and testing are all done in C++
-
Only Python (**kwargs) supports:
- Dynamic return value types;
Tip
In C++, the return type must be determined at compile time.
Function Prototypes
-
In Python:
# Any key name def func(**kwargs): ... # Limited key names (with default values) def func(*, name='empty_name', old=0): ...
-
In C++:
// Any key name auto func(Kwargs<> kwargs = {}) {...} // Limited key names (no need for default values) auto func(Kwargs<"name"_opt, "old"_opt> kwargs = {}) {...}
External Calls
-
In Python:
# Normal func(name='huanhuanonly', old=18) # Unexpected type func(name='huanhuanonly', old='18') # Reversed order func(old=18, name='huanhuanonly') # Empty arguments func()
-
In C++:
// Normal func({ {"name", "huanhuanonly"}, {"old", 18} }); // Unexpected type func({ {"name", "huanhuanonly"}, {"old", "18"} }); // Reversed order func({ {"old", 18}, {"name", "huanhuanonly"} }); // Empty arguments func()
Internal Value Access
-
In Python:
str(kwargs['name']) if 'name' in kwargs else 'empty_name' int(kwargs['old']) if 'old' in kwargs else 0
-
In C++:
kwargs["name"].valueOr<std::string>("empty_name") kwargs["old"].valueOr<int>(0) // kwargs["name"].hasValue() // Equivalent to // if 'name' in kwargs
struct Font
{
std::string faceName;
int size;
float escapement;
bool italic;
// Or Kwargs<> kwargs = {} without checking.
Font(Kwargs<
"faceName"_opt, /* Or */ "name"_opt,
"size"_opt,
"escapement"_opt,
"italic"_opt, /* Or */ "i"_opt> kwargs = {})
: faceName(kwargs["faceName"_opt or "name"].valueOr<std::string>())
, size(kwargs["size"].valueOr<int>(9))
, escapement(kwargs["escapement"].valueOr<float>(0.00f))
, italic(kwargs["italic"_opt or "i"].valueOr<bool>(false))
{ }
};
The following constructors for People
are all valid:
-
Font()
- Equal to:
Font{ std::string(), 9, 0.00f, false }
- Equal to:
-
Font({ })
- Equal to:
Font{ std::string(), 9, 0.00f, false }
- Equal to:
-
Font({ {"name", "Arial"}, {"italic", true} })
- Equal to:
Font{ std::string("Arial"), 9, 0.00f, true }
- Equal to:
-
Font({ {"italic", "true"}, {"name", "Arial"} })
- Equal to:
Font{ std::string("Arial"), 9, 0.00f, true }
- Equal to:
-
Font({ {"i", "True"}, {"faceName", "Arial"} })
- Equal to:
Font{ std::string("Arial"), 9, 0.00f, true }
- Equal to:
-
Font({ {"size", 18}, {"escapement", 45} })
- Equal to:
Font{ std::string(), 18, 45.00f, false }
- Equal to:
-
Font({ {"size", "18"}, {"escapement", "49.2"} })
- Equal to:
Font{ std::string(), 18, 49.20f, false }
- Equal to:
-
Font({ {"size", 18.8}, {"escapement", 49.2}, {"i", 't'} })
- Equal to:
Font{ std::string(), 18, 49.20f, true }
- Equal to:
-
In Python
def printList(value: list, /, *, sep = ', ', end = '\n'): if len(value) == 0: return for i in range(len(value) - 1): print(value[i], end=sep) print(value[-1], end=end)
-
In C++
void printList( const std::vector<int>& value, Kwargs<"sep"_opt, "end"_opt> kwargs = { }) { if (value.empty()) return; for (std::size_t i = 0; i < value.size() - 1; ++i) std::cout << value[i], std::cout << kwargs["sep"].valueOr<std::string_view>(", "); std::cout << value.back(); std::cout << kwargs["end"].valueOr<std::string_view>("\n"); }
Call:
-
In Python
printList([1, 4, 3, 3, 2, 2, 3], sep=' | ', end='.')
-
In C++
printList( {1, 4, 3, 3, 2, 2, 3}, { {"sep", " | "}, {"end", '.'} });
For more usage examples, click .
git clone https://github.com/huanhuanonly/cpp-kwargs.git
- CMakeList.txt
set (CPP_KWARGS_REPOS "https://github.com/huanhuanonly/cpp-kwargs.git")
set (CPP_KWARGS_PATH "${CMAKE_SOURCE_DIR}/cpp-kwargs")
include (FetchContent)
if (NOT EXISTS ${CPP_KWARGS_PATH})
FetchContent_Declare (
CppKwargs
GIT_REPOSITORY ${CPP_KWARGS_REPOS}
GIT_TAG main
GIT_SHALLOW TRUE
SOURCE_DIR ${CPP_KWARGS_PATH}
)
FetchContent_MakeAvailable (CppKwargs)
endif()
include_directories (${CPP_KWARGS_PATH})
- main.cpp
#include <CppKwargs.h>
Tip
This project only requires a single header file to run.
-
Define
KWARGSKEY_CASE_INSENSITIVE
before#include "CppKwargs.h"
:#ifndef KWARGSKEY_CASE_INSENSITIVE # define KWARGSKEY_CASE_INSENSITIVE #endif #include "CppKwargs.h"
-
Alternatively, add the following line to your project's CMakeList.txt file:
target_compile_definitions (YourExecutable PRIVATE KWARGSKEY_CASE_INSENSITIVE)
-
All integer and floating-point type conversions.
-
For all enumeration types
enum
is considered to be its underlying type (integer).
Tip
Even if the underlying type of enum
is char
/ uchar
, it will be treated as an integer (std::int8_t
/ std::uint8_t
).
-
std::string
$\longleftrightarrow$ std::string_view
. -
std::string
/std::string_view
$\longleftrightarrow$ const char*
. -
std::vector<char>
/std::array<char>
/std::string_view
$\longrightarrow$ const char*
(does not guarantee\0
terminator). -
const char*
/std::string
/std::string_view
$\longrightarrow$ Integer
/Floating point
. -
Integer
/Floating point
$\longrightarrow$ std::string
. -
const char*
/std::string
/std::string_view
$\longleftrightarrow$ char
/uchar
(takes the first character, returns\0
if empty). -
bool
$\longrightarrow$ const char*
/std::string
/std::string_view
("true"
or"false"
). -
"true"
/"True"
/"TRUE"
/'t'
/'T'
$\longrightarrow$ true
. -
"false"
/"False"
/"FALSE"
/'f'
/'F'
$\longrightarrow$ false
. -
Iterable containers (with
.begin()
,.end()
, and forward-iterator)$\longrightarrow$ Insertable containers.
Note
Both containers must have ::value_type
, but the value types don't need to match. If they don't, conversion will follow the above rules.
Insertable containers
Has one of the following member functions (in order):
.append()
.push_back()
.push()
.insert()
.push_front()
-
Copyright
$2024\text{-}2025$ Yang Huanhuan (3347484963@qq.com). All rights reserved. -
Created by Yang Huanhuan on
$December$ $29, 2024, 14:40:45$ . -
Goodbye
$2024$ , Hello$2025$ !