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_signature_checker.cc | 110 ++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 110 insertions(+) create mode 100644 fn_signature_checker.cc (limited to 'fn_signature_checker.cc') 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