#include <iostream>
template <int N>
constexpr size_t count_percents(const char (&s)[N]) {
size_t count = 0;
for (size_t i = 0; i < N; i++)
if (s[i] == '%') ++count;
return count;
}
template <int N, typename... Args>
constexpr std::string Sprintf(const char (&format)[N], Args&&... args) {
if (count_percents(format) != sizeof...(args))
throw std::invalid_argument("wrong number of placeholders in format string");
return (std::to_string(args) + ...);
}
int main() {
std::cout << Sprintf("%%", 1, 2); // outputs "12", ok
// ideally wouldn't compile (but does - then throws runtime exception)
std::cout << Sprintf("%", 1, 2);
}
I发现了这个答案
有帮助,但是它并没有解决我的用例,在该情况下,我希望根据传递给非consteval函数的参数数量编译时间错误。 (如果我想进行的所有编译时间检查仅取决于格式字符串本身的内容。)
there是您的示例的修改版本,该版本应有效:
#include <iostream>
#include <type_traits>
constexpr size_t count_percents(const char* s) {
size_t count = 0;
while (*s != '\0') {
if (*(s++) == '%') {
count++;
}
}
return count;
}
template <typename... Args>
struct format_args {
const char* format;
consteval format_args(const char* format) : format(format) {
if (count_percents(format) != sizeof...(Args)) {
throw std::invalid_argument("wrong number of placeholders in format string");
}
}
};
template <typename... Args>
constexpr std::string Sprintf(format_args<std::type_identity_t<Args>...> format, Args&&... args) {
return (std::to_string(args) + ...);
}
int main() {
std::cout << Sprintf("%%", 1, 2); // outputs "12", ok
// ideally wouldn't compile (but does - then throws runtime exception)
std::cout << Sprintf("%", 1, 2);
}
Args
传递给format_args
std::type_identity_t
。如果您像:
那样天真地声明它:constexpr std::string Sprintf(format_args<Args...> format, Args&&... args) {
// impl
}
...它不起作用,因为当编译器进行模板分辨率时,它会从左到右检查参数并尝试匹配它们。它将首先尝试从您传递的第一个参数的类型中推断出来。嗯,不能因为它是一个。因此,它尖叫了一个错误!
这里是here conthen派上用场的地方:它使
Args...
pack内部的the the the the nim in the non deded ContextInd contectiondecontectiondectessine contectiond contectiond contectisty什么应该是稍后的(从
const char*
的类型中可以)。