From f838e7c4aaa04d5084f6922aa516a845b19e78e9 Mon Sep 17 00:00:00 2001 From: Johannes Stoelp Date: Fri, 4 Oct 2024 20:10:05 +0200 Subject: fn: add simple fn signature checker example --- fn_alias.cc | 32 ++++++++++++++ fn_signature_checker.cc | 110 ++++++++++++++++++++++++++++++++++++++++++++++++ 2 files changed, 142 insertions(+) create mode 100644 fn_alias.cc create mode 100644 fn_signature_checker.cc diff --git a/fn_alias.cc b/fn_alias.cc new file mode 100644 index 0000000..2d9fd1d --- /dev/null +++ b/fn_alias.cc @@ -0,0 +1,32 @@ +#include +#include + +// Function alias. + +void say() { + std::puts("say"); +} + +inline constexpr auto say_alias = say; + +// Template function alias. +// +// One drawback is that template type deducation does not work through the +// function pointer. One would need to write some macro wrapper. + +template +auto add(T t, U u) -> decltype(t + u) { + return t + u; +} + +template +inline constexpr auto add_int = add; + +// Test me. + +int main() { + say(); + say_alias(); + + assert(add(2, 3) == add_int(3, 2)); +} diff --git a/fn_signature_checker.cc b/fn_signature_checker.cc new file mode 100644 index 0000000..985c719 --- /dev/null +++ b/fn_signature_checker.cc @@ -0,0 +1,110 @@ +#if 0 +set -xe +g++ -std=c++11 -fsyntax-only fn_signature_checker.cc || echo "EXPECTED FAILURE" +clang++ -std=c++11 -fsyntax-only fn_signature_checker.cc || echo "EXPECTED FAILURE" +g++ -std=c++20 -fsyntax-only fn_signature_checker.cc || echo "EXPECTED FAILURE" +clang++ -std=c++20 -fsyntax-only fn_signature_checker.cc || echo "EXPECTED FAILURE" +exit 0 +#endif + +#include + +// Function signature checker for generic functions. +// +// This demonstrates a way to do some simple function signature checking on +// template arguments w/o implementing the whole concept emulation with +// std::void_t prior to cpp20. This may not be the best solution, but it gives a +// small tool at hand which can easily be employed into older cpp code bases. +// +// Starting with cpp20, one can fully switch to concepts for this task. + +// -- PRE CPP20 ---------------------------------------------------------------- + +// (1) Primary template to extract the function signature type. +template +struct fn; + +// (2) Partial specialization for function types. +template +struct fn { + using type = Ret(Args...); +}; + +// (3) Partial specialization for function pointer types. +// +// This specialization is disabled on purpose as it allows for writing ambiguous +// checks for either non-static or static member functions. +// +// template +// struct fn { +// using type = Ret(Args...); +// }; + +// (4) Partial specialization for member function pointer types. +template +struct fn { + using type = Ret(Args...); +}; + +template +using fn_t = typename fn::type; + +template +void do_work() { + // Check for non-static member function. + // + // If the partial specialization (3) is enabled, this could also match a + // static member function T::get. + static_assert(std::is_same, fn_t>::value, + "T has no member function 'int get(int)'"); + // Check for non-static member function. + static_assert(std::is_same, fn_t>::value, + "T has no member function 'void set(int)'"); + // Check for static member function. + static_assert(std::is_same, fn_t>::value, + "T has no static function 'static int cnt()'"); +} + +struct good { + int get(int); + void set(int); + static int cnt(); +}; + +struct bad { + int get(int); + int set(); + static int cnt(); +}; + +void check() { + do_work(); + + // TODO: Enable to see a failing check due to wrong function signature. + // do_work(); +} + +// -- SINCE CPP20 -------------------------------------------------------------- + +#if __cplusplus >= 202002L +#include + +template +concept MyType = requires(T t) { + { t.get(int{}) } -> std::same_as; + { t.set(int{}) } -> std::same_as; + { T::cnt() } -> std::same_as; +}; + +template +void do_work2() { +} + +void check2() { + do_work2(); + + // TODO: Enable to see failing to satisfy the concept MyType. + // do_work2(); +} + +#endif -- cgit v1.2.3