From bbca292522ae26eac0c45bfde59936e6a354c597 Mon Sep 17 00:00:00 2001 From: Oliver Lee Date: Mon, 16 Jun 2025 18:00:57 -0700 Subject: [PATCH] reduce use of SFINAE to shorten error messages Remove SFINAE from user-facing functions to reduce the length of compiler errors. For example, the error for `eq(a == b)` instead of `eq(a, b)` is
before ``` external/toolchains_llvm++llvm+llvm_toolchain_llvm/bin/../include/c++/v1/__type_traits/invoke.h:314:1: error: no type named 'type' in 'std::invoke_result' 314 | using invoke_result_t = typename invoke_result<_Fn, _Args...>::type; | ^~~~~ external/skytest+/src/test.hpp:27:16: note: in instantiation of template type alias 'invoke_result_t' requested here 27 | std::invoke_result_t&, Args...>, | ^ external/toolchains_llvm++llvm+llvm_toolchain_llvm/bin/../include/c++/v1/__type_traits/conjunction.h:60:58: note: in instantiation of template class 'skytest::detail::returns_result<(lambda at sel/test/constant_test.cpp:26:7), int>' requested here 60 | struct conjunction<_Arg, _Args...> : conditional_t> {}; | ^ external/skytest+/src/test_param.hpp:117:7: note: in instantiation of template class 'std::conjunction, skytest::detail::returns_result<(lambda at sel/test/constant_test.cpp:26:7), float>, skytest::detail::returns_result<(lambda at sel/test/constant_test.cpp:26:7), double>>' requested here 117 | : std::conjunction>...> | ^ external/skytest+/src/test_param.hpp:127:7: note: in instantiation of template class 'skytest::detail::param_invocable_, (lambda at sel/test/constant_test.cpp:26:7), skytest::constexpr_params_t<1, 2.000000e+00, 3.000000e+00>>' requested here 127 | : param_invocable_, F, param_resolve_t> | ^ external/skytest+/src/test_param.hpp:131:43: note: in instantiation of template class 'skytest::detail::param_invocable<(lambda at sel/test/constant_test.cpp:26:7), skytest::param_ref_t>' requested here 131 | inline constexpr auto param_invocable_v = param_invocable::value; | ^ external/skytest+/src/test_param.hpp:252:11: note: in instantiation of variable template specialization 'skytest::detail::param_invocable_v' requested here 252 | param_invocable_v and | ^ external/skytest+/src/test_param.hpp:256:8: note: while substituting prior template arguments into non-type template parameter [with F = (lambda at sel/test/constant_test.cpp:26:7)] 256 | auto operator=(const F& func) && -> void | ^~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ 257 | { | ~ 258 | assign_impl( | ~~~~~~~~~~~~ 259 | param_sequence_t{}, | ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ 260 | param_bound_closure{func, params_}); | ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ 261 | } | ~ sel/test/constant_test.cpp:25:38: note: while substituting deduced template arguments into function template 'operator=' [with F = (lambda at sel/test/constant_test.cpp:26:7), $1 = (no value)] 25 | constexpr_params<1, 2.0F, 3.0> = // | ^ sel/test/constant_test.cpp:25:38: error: no viable overloaded '=' 24 | "constants always define a strong ordering"_ctest * | ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ 25 | constexpr_params<1, 2.0F, 3.0> = // | ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ ^ 26 | [](T value) { | ~~~~~~~~~~~~~~~~~~~~~~ 27 | auto a = sel::constant{value}; | ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ 28 | auto b = sel::constant{T{2} * value}; | ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ 29 | return expect( | ~~~~~~~~~~~~~~ 30 | eq(std::strong_ordering::less == (a <=> b)) and // | ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ 31 | eq(std::strong_ordering::greater, (b <=> a)) and // | ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ 32 | eq(std::strong_ordering::equal, (b <=> b)) | ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ 33 | ); | ~~ 34 | }; | ~ external/skytest+/src/test_param.hpp:256:8: note: candidate template ignored: substitution failure [with F = (lambda at sel/test/constant_test.cpp:26:7)] 256 | auto operator=(const F& func) && -> void | ^ external/skytest+/src/test_param.hpp:269:8: note: candidate template ignored: substitution failure [with F = (lambda at sel/test/constant_test.cpp:26:7)] 269 | auto operator=(const F& func) && -> void | ^ external/skytest+/src/test_param.hpp:174:7: note: candidate function (the implicit copy assignment operator) not viable: no known conversion from '(lambda at sel/test/constant_test.cpp:26:7)' to 'const parameterized_test, compile_time>' for 1st argument 174 | class parameterized_test | ^~~~~~~~~~~~~~~~~~ 3 errors generated. ```
after ``` external/skytest+/src/detail/predicate.hpp:35:18: error: no matching function for call to object of type 'const std::equal_to' 35 | auto value = static_cast(*this)(std::as_const(args)...); | ^~~~~~~~~~~~~~~~~~~~~~~~~~~~ sel/test/constant_test.cpp:30:13: note: in instantiation of function template specialization 'skytest::detail::predicate, skytest::detail::type_name, skytest::detail::pred_fmt::eq_>::operator()' requested here 30 | eq(std::strong_ordering::less == (a <=> b)) and // | ^ external/skytest+/src/test_param.hpp:161:26: note: in instantiation of function template specialization 'main()::(anonymous class)::operator()' requested here 161 | return [] { return func(get(params)); }; | ^ external/skytest+/src/test_param.hpp:161:17: note: while substituting into a lambda expression here 161 | return [] { return func(get(params)); }; | ^ external/skytest+/src/test_param.hpp:231:15: note: in instantiation of function template specialization 'skytest::detail::param_bound_static_closure::operator[]<2UL>' requested here 231 | g[constant{}], | ^ external/skytest+/src/test_param.hpp:253:7: note: in instantiation of function template specialization 'skytest::detail::parameterized_test, skytest::detail::test_style::compile_time>::assign_impl<0UL, 1UL, 2UL, skytest::detail::param_bound_static_closure>' requested here 253 | assign_impl( | ^ sel/test/constant_test.cpp:25:38: note: in instantiation of function template specialization 'skytest::detail::parameterized_test, skytest::detail::test_style::compile_time>::operator=<(lambda at sel/test/constant_test.cpp:26:7)>' requested here 25 | constexpr_params<1, 2.0F, 3.0> = // | ^ external/toolchains_llvm++llvm+llvm_toolchain_llvm/bin/../include/c++/v1/__functional/operations.h:308:60: note: candidate function template not viable: requires 2 arguments, but 1 was provided 308 | _LIBCPP_CONSTEXPR_SINCE_CXX14 _LIBCPP_HIDE_FROM_ABI auto operator()(_T1&& __t, _T2&& __u) const | ^ ~~~~~~~~~~~~~~~~~~~~ 1 error generated. ```
Change-Id: Ibc7ab9d85dc732ae7b895093147584211ef713ac --- README.md | 6 ++-- example/ctest_fail.log | 6 ++-- src/detail/predicate.hpp | 11 ++++--- src/test_param.hpp | 62 +++++++++++++++------------------------- 4 files changed, 34 insertions(+), 51 deletions(-) diff --git a/README.md b/README.md index ac7e695..8cd5015 100644 --- a/README.md +++ b/README.md @@ -94,9 +94,9 @@ results in the follow build error (snippet): external/llvm_toolchain_llvm/bin/../include/c++/v1/__functional/operations.h:374:37: note: read of non-const variable 'n' is not allowed in a constant expression 374 | return std::forward<_T1>(__t) < std::forward<_T2>(__u); | ^ -./src/detail/predicate.hpp:38:24: note: in call to 'static_cast &>(*this).operator()(0, n)' - 38 | const auto value = static_cast(*this)(std::as_const(args)...); - | ^~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +./src/detail/predicate.hpp:35:18: note: in call to 'static_cast &>(*this).operator()(0, n)' + 35 | auto value = static_cast(*this)(std::as_const(args)...); + | ^~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ example/ctest_fail.cpp:10:47: note: (skipping 2 calls in backtrace; use -fconstexpr-backtrace-limit=0 to see all) 10 | "read non-const"_ctest = [] { return expect(lt(0, n)); }; | ^ diff --git a/example/ctest_fail.log b/example/ctest_fail.log index 547b538..6459545 100644 --- a/example/ctest_fail.log +++ b/example/ctest_fail.log @@ -10,9 +10,9 @@ external/llvm_toolchain_llvm/bin/../include/c++/v1/__functional/operations.h:374:37: note: read of non-const variable 'n' is not allowed in a constant expression 374 | return std::forward<_T1>(__t) < std::forward<_T2>(__u); | ^ -./src/detail/predicate.hpp:38:24: note: in call to 'static_cast &>(*this).operator()(0, n)' - 38 | const auto value = static_cast(*this)(std::as_const(args)...); - | ^~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +./src/detail/predicate.hpp:35:18: note: in call to 'static_cast &>(*this).operator()(0, n)' + 35 | auto value = static_cast(*this)(std::as_const(args)...); + | ^~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ example/ctest_fail.cpp:10:47: note: (skipping 2 calls in backtrace; use -fconstexpr-backtrace-limit=0 to see all) 10 | "read non-const"_ctest = [] { return expect(lt(0, n)); }; | ^ diff --git a/src/detail/predicate.hpp b/src/detail/predicate.hpp index 18e791e..0c23f47 100644 --- a/src/detail/predicate.hpp +++ b/src/detail/predicate.hpp @@ -29,15 +29,14 @@ struct predicate : F constexpr predicate(T&& f) : F{std::forward(f)} {} - template < - class... Ts, - class = - std::enable_if_t>> + template constexpr auto operator()(Ts&&... args) const { - const auto value = static_cast(*this)(std::as_const(args)...); + auto value = static_cast(*this)(std::as_const(args)...); + return relation...>{ - std::tuple...>{std::forward(args)...}, value}; + std::tuple...>{std::forward(args)...}, + std::move(value)}; } }; diff --git a/src/test_param.hpp b/src/test_param.hpp index 9b809d0..2bc84fb 100644 --- a/src/test_param.hpp +++ b/src/test_param.hpp @@ -152,21 +152,14 @@ struct param_bound_closure template struct param_bound_static_closure { - template < - std::size_t I, - class P = remove_cvref_t, - std::enable_if_t, bool> = true> - constexpr auto operator[](constant) const - { - return [] { return func(get(params)); }; - } - template < - std::size_t I, - class P = remove_cvref_t, - std::enable_if_t, bool> = true> + template constexpr auto operator[](constant) const { - return [] { return func(params.begin()[I]); }; + if constexpr (is_range_v) { + return [] { return func(params.begin()[I]); }; + } else { + return [] { return func(get(params)); }; + } } }; @@ -246,34 +239,25 @@ class parameterized_test : params_{params}, basename_{basename} {} - template < - class F, - std::enable_if_t< - param_invocable_v and - not(is_static_closure_constructible_v and - has_static_value_v), - bool> = true> + template auto operator=(const F& func) && -> void { - assign_impl( - param_sequence_t{}, - param_bound_closure{func, params_}); - } - template < - class F, - std::enable_if_t< - param_invocable_v and - is_static_closure_constructible_v and - has_static_value_v, - bool> = true> - auto operator=(const F& func) && -> void - { - static const auto f = func; - static constexpr const auto& p = params_type::value; - - assign_impl( - std::make_index_sequence>{}, - param_bound_static_closure{}); + constexpr auto is_constexpr_invocable = + is_static_closure_constructible_v and + has_static_value_v; + + if constexpr (is_constexpr_invocable) { + static const auto f = func; + static constexpr const auto& p = params_type::value; + + assign_impl( + std::make_index_sequence>{}, + param_bound_static_closure{}); + } else { + assign_impl( + param_sequence_t{}, + param_bound_closure{func, params_}); + } } };