Skip to content
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

User-defined literals for format and named arguments #204

Merged
merged 2 commits into from
Oct 7, 2015
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
53 changes: 53 additions & 0 deletions format.h
Original file line number Diff line number Diff line change
Expand Up @@ -177,6 +177,16 @@ inline uint32_t clzll(uint64_t x) {
TypeName& operator=(const TypeName&)
#endif

#ifndef FMT_USE_USER_DEFINED_LITERALS
// All compilers which support UDLs also support variadic templates. This
// makes the fmt::literals implementation easier. However, an explicit check
// for variadic templates is added here just in case.
# define FMT_USE_USER_DEFINED_LITERALS \
FMT_USE_VARIADIC_TEMPLATES && \
(FMT_HAS_FEATURE(cxx_user_literals) || \
(FMT_GCC_VERSION >= 407 && FMT_HAS_GXX_CXX11) || _MSC_VER >= 1900)
#endif

#ifndef FMT_ASSERT
# define FMT_ASSERT(condition, message) assert((condition) && message)
#endif
Expand Down Expand Up @@ -3005,6 +3015,49 @@ FMT_VARIADIC(int, printf, CStringRef)
FMT_VARIADIC(int, fprintf, std::FILE *, CStringRef)
}

#if FMT_USE_USER_DEFINED_LITERALS
namespace fmt {
namespace internal {

template <typename Char>
struct UdlFormat {
const Char *str;

template <typename... Args>
auto operator()(Args && ... args) const
-> decltype(format(str, std::forward<Args>(args)...)) {
return format(str, std::forward<Args>(args)...);
}
};

template <typename Char>
struct UdlArg {
const Char *str;

template <typename T>
NamedArg<Char> operator=(T &&value) const {
return {str, std::forward<T>(value)};
}
};

} // namespace internal

inline namespace literals {

inline internal::UdlFormat<char>
operator"" _format(const char *s, std::size_t) { return {s}; }
inline internal::UdlFormat<wchar_t>
operator"" _format(const wchar_t *s, std::size_t) { return {s}; }

inline internal::UdlArg<char>
operator"" _a(const char *s, std::size_t) { return {s}; }
inline internal::UdlArg<wchar_t>
operator"" _a(const wchar_t *s, std::size_t) { return {s}; }

} // inline namespace literals
} // namespace fmt
#endif // FMT_USE_USER_DEFINED_LITERALS

// Restore warnings.
#if FMT_GCC_VERSION >= 406
# pragma GCC diagnostic pop
Expand Down
22 changes: 22 additions & 0 deletions test/format-test.cc
Original file line number Diff line number Diff line change
Expand Up @@ -1602,3 +1602,25 @@ TEST(FormatTest, MaxArgs) {
fmt::format("{}{}{}{}{}{}{}{}{}{}{}{}{}{}{}",
0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 'a', 'b', 'c', 'd', 'e'));
}

#if FMT_USE_USER_DEFINED_LITERALS
using namespace fmt::literals;

TEST(LiteralsTest, Format) {
EXPECT_EQ(format("{}c{}", "ab", 1), "{}c{}"_format("ab", 1));
EXPECT_EQ(format(L"{}c{}", L"ab", 1), L"{}c{}"_format(L"ab", 1));
}

TEST(LiteralsTest, NamedArg) {
EXPECT_EQ(format("{first}{second}{first}{third}",
fmt::arg("first", "abra"), fmt::arg("second", "cad"),
fmt::arg("third", 99)),
format("{first}{second}{first}{third}",
"first"_a="abra", "second"_a="cad", "third"_a=99));
EXPECT_EQ(format(L"{first}{second}{first}{third}",
fmt::arg(L"first", L"abra"), fmt::arg(L"second", L"cad"),
fmt::arg(L"third", 99)),
format(L"{first}{second}{first}{third}",
L"first"_a=L"abra", L"second"_a=L"cad", L"third"_a=99));
}
#endif // FMT_USE_USER_DEFINED_LITERALS