First of all, some demo code:
#include <format>
#include <iostream>
// OVERLOAD 1
template <typename... Ts>
inline void write(const std::format_string<Ts...> &fmtStr, Ts &&...args)
{
std::string msg{std::format(fmtStr, std::forward<Ts>(args)...)};
std::cout << msg << '\n';
}
// OVERLOAD 2
template <typename... Ts>
inline void write(const std::string_view fmtStr, Ts &&...args)
{
std::string msg{std::vformat(fmtStr, std::make_format_args(std::forward<Ts>(args)...))};
std::cout << msg << '\n';
}
std::string foo()
{
return "Another test {}";
}
int main()
{
write("Test {}", "a value"); // CALL 1 ambiguous call to overloaded function
write(foo(), "a value"); // CALL 2 ambiguous call to overloaded function
write(std::format_string<int>("Test3 {}"), 3); // CALL 3
write(std::string_view("Test4 {}"), 3); // CALL 4
}
The vision here is to have call 1 find overload 1, since std::format_string requires fmtStr to be consteval, and likewise, call 2 should find overload 2 because the value from foo is not consteval.
Questions:
Yes you will need two more overloads (to get better matches with const char*
and std::string
)
#include <type_traits>
#include <format>
#include <iostream>
// OVERLOAD 1
template <typename... Ts>
inline void write(std::format_string<Ts...>&& fmtStr, Ts&&...args)
{
std::string msg{std::format(fmtStr, std::forward<Ts>(args)...)};
std::cout << msg << '\n';
}
// OVERLOAD 2
template <typename... Ts>
inline auto write(std::string_view fmtStr, Ts&&...args)
{
std::string msg{std::vformat(fmtStr, std::make_format_args(std::forward<Ts>(args)...))};
std::cout << msg << '\n';
}
// OVERLOAD 3
template <typename... Ts>
inline auto write(const char* fmtStr, Ts&&...args)
{
std::string msg{std::vformat(fmtStr, std::make_format_args(std::forward<Ts>(args)...))};
std::cout << msg << '\n';
}
// OVERLOAD 4
template <typename... Ts>
inline auto write(const std::string& fmtStr, Ts&&...args)
{
std::string msg{std::vformat(fmtStr, std::make_format_args(std::forward<Ts>(args)...))};
std::cout << msg << '\n';
}
std::string foo()
{
return "Another test {}";
}
int main()
{
write("Test {}", "a value"); // CALL 1 ambiguous call to overloaded function
write(foo(), "a value"); // CALL 2 ambiguous call to overloaded function
write(std::format_string<int>("Test3 {}"), 3); // CALL 3
write(std::string_view("Test4 {}"), 3); // CALL 4
}