Last active
July 24, 2024 23:49
-
-
Save Nekrolm/31c8e811f96431c316e39d4096957f77 to your computer and use it in GitHub Desktop.
compile time boolean option list with C++23
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
#include <string> | |
#include <string_view> | |
#include <iostream> | |
#include <concepts> | |
void check_length(std::string_view sv) | |
{ std::cout << "check len\n"; } | |
void check_content(std::string_view sv) | |
{ std::cout << "check content\n"; } | |
// ... more other checks | |
// You had a function: | |
void my_great_function(const std::string& input) { | |
check_length(input); | |
check_content(input); | |
std::cout << "do great! " << input << "\n"; | |
} | |
// then you'd decided you need an option to bypass checks: | |
// Option 1: BAD | |
void my_great_function_bad(const std::string& input, bool len_check = true, bool content_check = true) { }; | |
// Option 2: Better | |
struct CheckOptions { bool len; bool content; }; | |
void my_great_function_better(const std::string& input, CheckOptions opts = {.len = true, .content = true}) { } | |
// Option 3: Best | |
template <class T, auto... Vars> | |
concept OneOf = (std::same_as<T, decltype(Vars)> || ...); | |
constexpr struct {} SkipLengthCheck; | |
constexpr struct {} SkipContentCheck; | |
void my_great_function_best(const std::string& input, | |
OneOf<SkipLengthCheck, SkipContentCheck> auto... opts) { | |
struct: decltype(opts)... {} OptsSet; | |
if constexpr (not requires { auto(SkipLengthCheck) = OptsSet; }) { | |
check_length(input); | |
} | |
if constexpr (not requires { auto(SkipContentCheck) = OptsSet; }) { | |
check_content(input); | |
} | |
std::cout << "do great! " << input << "\n"; | |
} | |
int main() { | |
std::cout << "-- call no parameters:\n"; | |
my_great_function_best("hello"); | |
std::cout << "-- call skip len:\n"; | |
my_great_function_best("hello", SkipLengthCheck); | |
std::cout << "-- call skip content:\n"; | |
my_great_function_best("hello", SkipContentCheck); | |
std::cout << "-- call skip both: \n"; | |
my_great_function_best("hello", SkipContentCheck, SkipLengthCheck); | |
std::cout << "-- call skip both (different params order): \n"; | |
my_great_function_best("hello", SkipLengthCheck, SkipContentCheck); | |
} | |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
#include <string> | |
#include <string_view> | |
#include <iostream> | |
#include <concepts> | |
void check_length(std::string_view sv) | |
{ std::cout << "check len\n"; } | |
void check_content(std::string_view sv) | |
{ std::cout << "check content\n"; } | |
// ... more other checks | |
// You had a function: | |
void my_great_function(const std::string& input) { | |
check_length(input); | |
check_content(input); | |
std::cout << "do great! " << input << "\n"; | |
} | |
// then you'd decided you need an option to add checks, disabled by default | |
// Option 1: BAD | |
void my_great_function_bad(const std::string& input, bool len_check = true, bool content_check = true) { }; | |
// Option 2: Better | |
struct CheckOptions { bool len; bool content; }; | |
void my_great_function_better(const std::string& input, CheckOptions opts = {.len = true, .content = true}) { } | |
// Option 3: Best | |
template <class T, auto... Vars> | |
concept OneOf = (std::same_as<T, decltype(Vars)> || ...); | |
constexpr auto CheckLength = [](const std::string& s) { | |
std::cout << "check len\n"; | |
}; | |
constexpr auto CheckContent = [](const std::string& s) { | |
std::cout << "check content\n"; | |
}; | |
constexpr auto AdditionalCheckLength = [](const std::string& s, int) { | |
std::cout << "add check len\n"; | |
}; | |
constexpr auto AdditionalCheckContent = [](const std::string& s, int) { | |
std::cout << "add check content\n"; | |
}; | |
void my_great_function_best(const std::string& input, | |
OneOf<CheckLength, | |
CheckContent, | |
AdditionalCheckLength, | |
AdditionalCheckContent> auto... checks) { | |
constexpr static struct: decltype(checks)... {} CheckList; | |
constexpr static auto for_checks_do = [](auto apply, auto... checks) { | |
([](auto check, auto apply) { | |
if constexpr (requires { check = CheckList; }) { | |
apply(check); | |
} | |
}(checks, apply), ...); | |
}; | |
for_checks_do([&input](auto check) { check(input); }, | |
CheckLength, CheckContent | |
); | |
for_checks_do([&input](auto check) { check(input, 42); }, | |
AdditionalCheckLength, AdditionalCheckContent | |
); | |
std::cout << "do great! " << input << "\n"; | |
} | |
int main() { | |
my_great_function_best("hello", CheckLength, AdditionalCheckContent); | |
} | |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment