在编译时计算函数参数
Counting function arguments at compile time
我正在尝试计算编译时函数的参数数量(我将 sprintf 包装在一些模板中以进行编译时检查和类型安全)。我需要在编译时检查参数的数量是否与格式化占位符的数量相匹配。第一步非常简单:
template <typename... Args>
constexpr u32
CountArgs(Args&&... args)
{
return sizeof...(args);
}
constexpr u32
CountFormatSpecifiers(c8* format);
template <typename... Args>
c8*
String_FormatImpl(c8* format, Args&&... args);
#define String_Format(format, ...) \
String_FormatImpl(format, __VA_ARGS__); \
static_assert(CountFormatSpecifiers(format) == CountArgs(__VA_ARGS__));
但这对于某些类型的论点是无效的。即,传递引用时。
int x = 0;
int& xRef = x;
String_Format("%", xRef);
编译器抱怨 CountArgs(__VA_ARGS__)
因为 xRef
不是常量表达式。我不需要价值,只需要计算它的能力。我可以将它包装在 sizeof
或类似的东西中,但是当我只有 __VA_ARGS__
可以使用时,这很难。
你可以把你的宏改成这样
#define String_Format(format, ...) \
String_FormatImpl<CountFormatSpecifiers(format)>(format, __VA_ARGS__);
template <std::size_t I, typename... Args>
void String_FormatImpl(const char* format, Args&&...) {
static_assert(I == sizeof...(Args));
...
}
也许使用 decltype()
和 std::integral_constant
?
我的意思是...您可以声明(仅声明:不需要定义它)以下函数(编辑:已修改,遵循 Davis Herring 的建议(谢谢!),以接受 const 引用;这允许工作也有不可复制的类型)
template <typename ... Args>
std::integral_constant<std::size_t, sizeof...(Args)> CArgs (Args const & ...);
并使用它,例如
#define bar(num, ...) \
static_assert(num == decltype(CArgs(__VA_ARGS__))::value);
这样您就不会在 static_assert()
中使用 __VA_ARGS__
值,而是使用接受 __VA_ARGS__
.
的函数返回的类型
并且返回的类型 (std::integral_constant<std::size_t, sizeof...(Args)>
) 包含参数的数量(可通过 ::value
访问),作为编译时常量。
下面是一个完整的编译示例
#include <type_traits>
template <typename ... Args>
std::integral_constant<std::size_t, sizeof...(Args)> CArgs (Args const & ...);
#define bar(num, ...) \
static_assert(num == decltype(CArgs(__VA_ARGS__))::value);
int main()
{
int x = 0;
int& xRef = x;
//..VV number of the following arguments
bar(3u, x, xRef, 42);
}
我正在尝试计算编译时函数的参数数量(我将 sprintf 包装在一些模板中以进行编译时检查和类型安全)。我需要在编译时检查参数的数量是否与格式化占位符的数量相匹配。第一步非常简单:
template <typename... Args>
constexpr u32
CountArgs(Args&&... args)
{
return sizeof...(args);
}
constexpr u32
CountFormatSpecifiers(c8* format);
template <typename... Args>
c8*
String_FormatImpl(c8* format, Args&&... args);
#define String_Format(format, ...) \
String_FormatImpl(format, __VA_ARGS__); \
static_assert(CountFormatSpecifiers(format) == CountArgs(__VA_ARGS__));
但这对于某些类型的论点是无效的。即,传递引用时。
int x = 0;
int& xRef = x;
String_Format("%", xRef);
编译器抱怨 CountArgs(__VA_ARGS__)
因为 xRef
不是常量表达式。我不需要价值,只需要计算它的能力。我可以将它包装在 sizeof
或类似的东西中,但是当我只有 __VA_ARGS__
可以使用时,这很难。
你可以把你的宏改成这样
#define String_Format(format, ...) \
String_FormatImpl<CountFormatSpecifiers(format)>(format, __VA_ARGS__);
template <std::size_t I, typename... Args>
void String_FormatImpl(const char* format, Args&&...) {
static_assert(I == sizeof...(Args));
...
}
也许使用 decltype()
和 std::integral_constant
?
我的意思是...您可以声明(仅声明:不需要定义它)以下函数(编辑:已修改,遵循 Davis Herring 的建议(谢谢!),以接受 const 引用;这允许工作也有不可复制的类型)
template <typename ... Args>
std::integral_constant<std::size_t, sizeof...(Args)> CArgs (Args const & ...);
并使用它,例如
#define bar(num, ...) \
static_assert(num == decltype(CArgs(__VA_ARGS__))::value);
这样您就不会在 static_assert()
中使用 __VA_ARGS__
值,而是使用接受 __VA_ARGS__
.
并且返回的类型 (std::integral_constant<std::size_t, sizeof...(Args)>
) 包含参数的数量(可通过 ::value
访问),作为编译时常量。
下面是一个完整的编译示例
#include <type_traits>
template <typename ... Args>
std::integral_constant<std::size_t, sizeof...(Args)> CArgs (Args const & ...);
#define bar(num, ...) \
static_assert(num == decltype(CArgs(__VA_ARGS__))::value);
int main()
{
int x = 0;
int& xRef = x;
//..VV number of the following arguments
bar(3u, x, xRef, 42);
}