New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

No validation on number of arguments? #492

Closed
bryceschober opened this Issue Apr 3, 2017 · 5 comments

Comments

Projects
None yet
4 participants
@bryceschober

bryceschober commented Apr 3, 2017

There doesn't seem to be any validation on the number of arguments passed matching the number in the format, at least in my usage of the writer api. Since fmtlib was advertised as a "safe" alternative to printf(), I guess I assumed that it would implement an equivalent of the compile-time checking of -Wformat, which does warn about argument count mismatches. Am I doing something wrong, or just expecting too much of fmtlib?

@vitaut

This comment has been minimized.

Show comment
Hide comment
@vitaut

vitaut Apr 5, 2017

Contributor

Unfortunately compile-time checks are not supported although there are some tricks in #62 for printf formatting.

As for checking the arguments, the library follows Python's str.format conventions and reports an error when trying to access non-existent argument (or argument of a wrong type), but it's OK to pass more arguments than needed.

Contributor

vitaut commented Apr 5, 2017

Unfortunately compile-time checks are not supported although there are some tricks in #62 for printf formatting.

As for checking the arguments, the library follows Python's str.format conventions and reports an error when trying to access non-existent argument (or argument of a wrong type), but it's OK to pass more arguments than needed.

@vitaut vitaut closed this Apr 5, 2017

@foonathan

This comment has been minimized.

Show comment
Hide comment
@foonathan

foonathan Apr 5, 2017

Collaborator

Have you considered doing something with UDLs?

Like: "Hello, {}!"_format which creates a format_str<1> object containing the format string itself and the number of arguments. Then simply another format() overload accepting this objects that can do static_assert() with sizeof...(Args). With C++14 constexpr it's pretty straightforward, with 11 also easy, just a little verbose and ugly.

Collaborator

foonathan commented Apr 5, 2017

Have you considered doing something with UDLs?

Like: "Hello, {}!"_format which creates a format_str<1> object containing the format string itself and the number of arguments. Then simply another format() overload accepting this objects that can do static_assert() with sizeof...(Args). With C++14 constexpr it's pretty straightforward, with 11 also easy, just a little verbose and ugly.

@dean0x7d

This comment has been minimized.

Show comment
Hide comment
@dean0x7d

dean0x7d Apr 6, 2017

Contributor

@foonathan Unfortunately, UDLs don't help here because there is no way to get type-system constants out of a constexpr function. The following seems like it should work, but it does not:

#include <type_traits>

constexpr auto operator""_size(char const*, std::size_t size) {
    return std::integral_constant<std::size_t, size>{};
    //                                         ^~~~
    // error: non-type template argument is not a constant expression
}

int main() {
    static_assert("hello"_size.value == 5, "");
}

The issue is that constexpr functions must be callable with either compiletime or runtime arguments, so no argument-dependent types can be generated. Up to and including C++17, the only way to get around this is by using macros... but it's as ugly as it sounds.

This could be solved if future standards allow overloading on the constexprness of the arguments or perhaps with static reflection (I haven't kept up with the reflection proposals, so I'm just guessing on the latter).

Contributor

dean0x7d commented Apr 6, 2017

@foonathan Unfortunately, UDLs don't help here because there is no way to get type-system constants out of a constexpr function. The following seems like it should work, but it does not:

#include <type_traits>

constexpr auto operator""_size(char const*, std::size_t size) {
    return std::integral_constant<std::size_t, size>{};
    //                                         ^~~~
    // error: non-type template argument is not a constant expression
}

int main() {
    static_assert("hello"_size.value == 5, "");
}

The issue is that constexpr functions must be callable with either compiletime or runtime arguments, so no argument-dependent types can be generated. Up to and including C++17, the only way to get around this is by using macros... but it's as ugly as it sounds.

This could be solved if future standards allow overloading on the constexprness of the arguments or perhaps with static reflection (I haven't kept up with the reflection proposals, so I'm just guessing on the latter).

@foonathan

This comment has been minimized.

Show comment
Hide comment
@foonathan

foonathan Apr 6, 2017

Collaborator

There's a UDL version that takes the chars at non-type template argument... but not for string literals, damn it, you're right.

Collaborator

foonathan commented Apr 6, 2017

There's a UDL version that takes the chars at non-type template argument... but not for string literals, damn it, you're right.

@vitaut

This comment has been minimized.

Show comment
Hide comment
@vitaut

vitaut Nov 6, 2017

Contributor

Compile-time format string checks are now available: http://zverovich.net/2017/11/05/compile-time-format-strings.html

Contributor

vitaut commented Nov 6, 2017

Compile-time format string checks are now available: http://zverovich.net/2017/11/05/compile-time-format-strings.html

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment