summaryrefslogtreecommitdiff
path: root/absl/strings/internal/str_format/bind.h
diff options
context:
space:
mode:
Diffstat (limited to 'absl/strings/internal/str_format/bind.h')
-rw-r--r--absl/strings/internal/str_format/bind.h47
1 files changed, 39 insertions, 8 deletions
diff --git a/absl/strings/internal/str_format/bind.h b/absl/strings/internal/str_format/bind.h
index 267cc0ef..80f29654 100644
--- a/absl/strings/internal/str_format/bind.h
+++ b/absl/strings/internal/str_format/bind.h
@@ -25,6 +25,7 @@
#include "absl/strings/internal/str_format/checker.h"
#include "absl/strings/internal/str_format/parser.h"
#include "absl/types/span.h"
+#include "absl/utility/utility.h"
namespace absl {
ABSL_NAMESPACE_BEGIN
@@ -87,6 +88,36 @@ class FormatSpecTemplate
: public MakeDependent<UntypedFormatSpec, Args...>::type {
using Base = typename MakeDependent<UntypedFormatSpec, Args...>::type;
+ template <bool res>
+ struct ErrorMaker {
+ constexpr bool operator()(int) const { return res; }
+ };
+
+ template <int i, int j>
+ static constexpr bool CheckArity(ErrorMaker<true> SpecifierCount = {},
+ ErrorMaker<i == j> ParametersPassed = {}) {
+ static_assert(SpecifierCount(i) == ParametersPassed(j),
+ "Number of arguments passed must match the number of "
+ "conversion specifiers.");
+ return true;
+ }
+
+ template <FormatConversionCharSet specified, FormatConversionCharSet passed,
+ int arg>
+ static constexpr bool CheckMatch(
+ ErrorMaker<Contains(specified, passed)> MismatchedArgumentNumber = {}) {
+ static_assert(MismatchedArgumentNumber(arg),
+ "Passed argument must match specified format.");
+ return true;
+ }
+
+ template <FormatConversionCharSet... C, size_t... I>
+ static bool CheckMatches(absl::index_sequence<I...>) {
+ bool res[] = {true, CheckMatch<Args, C, I + 1>()...};
+ (void)res;
+ return true;
+ }
+
public:
#ifdef ABSL_INTERNAL_ENABLE_FORMAT_CHECKER
@@ -100,7 +131,7 @@ class FormatSpecTemplate
// We use the 'unavailable' attribute to give a better compiler error than
// just 'method is deleted'.
// To avoid checking the format twice, we just check that the format is
- // constexpr. If is it valid, then the overload below will kick in.
+ // constexpr. If it is valid, then the overload below will kick in.
// We add the template here to make this overload have lower priority.
template <typename = void>
FormatSpecTemplate(const char* s) // NOLINT
@@ -112,7 +143,8 @@ class FormatSpecTemplate
template <typename T = void>
FormatSpecTemplate(string_view s) // NOLINT
__attribute__((enable_if(str_format_internal::EnsureConstexpr(s),
- "constexpr trap"))) {
+ "constexpr trap")))
+ : Base("to avoid noise in the compiler error") {
static_assert(sizeof(T*) == 0,
"Format specified does not match the arguments passed.");
}
@@ -133,13 +165,12 @@ class FormatSpecTemplate
#endif // ABSL_INTERNAL_ENABLE_FORMAT_CHECKER
- template <
- FormatConversionCharSet... C,
- typename = typename std::enable_if<sizeof...(C) == sizeof...(Args)>::type,
- typename = typename std::enable_if<AllOf(Contains(Args,
- C)...)>::type>
+ template <FormatConversionCharSet... C>
FormatSpecTemplate(const ExtendedParsedFormat<C...>& pc) // NOLINT
- : Base(&pc) {}
+ : Base(&pc) {
+ CheckArity<sizeof...(C), sizeof...(Args)>();
+ CheckMatches<C...>(absl::make_index_sequence<sizeof...(C)>{});
+ }
};
class Streamable {