#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>::value, "T has no member function 'int get(int)'"); // Check for non-static member function. static_assert(std::is_same>::value, "T has no member function 'void set(int)'"); // Check for static member function. static_assert(std::is_same>::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