HiveBrain v1.2.0
Get Started
← Back to all entries
snippetcppMinor

Compile-time printf-style format checking

Submitted by: @import:stackexchange-codereview··
0
Viewed 0 times
formatcompilecheckingtimestyleprintf

Problem

Inspired by this open ticket on Boost, this seeks to complete the work there.

Given a printf-style format string and associated arguments, a static_assert is performed on whether the format string and arguments are valid.

I'm particularly interested in:

  • Have I covered all possible format strings?



  • Am I doing this in the most efficient way?



This includes changes based on the comments from @Loki Astari on the previous iteration of this code here.

Here is the below code running on ideone.

```
#include
#include
#include
#include
#include

#ifndef BOOST_PP_VARIADICS
# define BOOST_PP_VARIADICS
#endif
#include

template
struct Format
{
template
static constexpr bool check(const char (&fmt)[N], std::size_t n);
};

//////////////////////

template
constexpr bool checkValidFormats(const char (&fmt)[N], size_t n, char c)
{
return n >= N ?
throw std::logic_error("invalid format for type")
: fmt[n] == c ?
true
: checkValidFormats(fmt, n + 1, c);
}

template
struct Type;

#define SUPPORTED_TYPE(T, Fmts) \
template<> \
struct Type \
{ \
template \
constexpr static bool check(const char (&fmt)[N], std::size_t n) \
{ \
return n >= N ? \
throw std::logic_error("invalid format for type") \
: checkValidFormats(Fmts, 0, fmt[n]); \
} \
}

SUPPORTED_TYPE(char, "c");
SUPPORTED_TYPE(int8_t, "cd");
SUPPORTED_TYPE(uint8_t, "cu");
SUPPORTED_TYPE(int16_t, "d");
SUPPORTED_TYPE(uint16_t, "u");
SUPPORTED_TYPE(int32_t, "d");
SUPPORTED_TYPE(uint32_t, "u");
SUPPORTED_TYPE(char*, "s");
SUPPORTED_TYPE(unsigned char*, "s");
SUPPORTED_TYPE(const char*, "s");
SUPPORTED_TYPE(std::string, "s");
SUPPORTED_TYPE(boost::string_ref, "s");
SUPPORTED_TYPE(double, "f");
SUPPORTED_TYPE(float, "f");

#define SUPPORTED_LL_TYPE(T, C) \
template<> \
struct Type \
{ \
templ

Solution

Unfortunately I don't have time to do a full review, I can only offer some nitpicks that are a bit too big to fit in a comment...
Inconsistent use of size_t and std::size_t

For example here:

template
constexpr bool isLiteralPercent(const char (&fmt)[N], std::size_t n)


There are other places too.
Prefer the _t helpers for type_traits type templates in stl.

In struct Argument, this:

return Type::type>::check(fmt, n) &&
            Format::check(fmt, n + 1);


could be:

return Type>::check(fmt, n) &&
            Format::check(fmt, n + 1);


to get rid of the typename nonsense. :)

Code Snippets

template<size_t N>
constexpr bool isLiteralPercent(const char (&fmt)[N], std::size_t n)
return Type< typename std::decay<T>::type>::check(fmt, n) &&
            Format<Ts...>::check(fmt, n + 1);
return Type<std::decay_t<T>>::check(fmt, n) &&
            Format<Ts...>::check(fmt, n + 1);

Context

StackExchange Code Review Q#85031, answer score: 6

Revisions (0)

No revisions yet.