snippetcppMinor
Compile-time printf-style format checking
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
I'm particularly interested in:
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
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
For example here:
There are other places too.
Prefer the
In
could be:
to get rid of the
Inconsistent use of
size_t and std::size_tFor 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.