Vla*_*iev 19 c++ variadic-functions variadic-templates c++11
可变参数模板有很多优点,但有时候<cstdarg>应该使用C风格的可变参数函数(使用)吗?
eer*_*ika 25
如果您提供带有C++实现的C API,则模板不是API的选项.Varargs是.
如果需要支持不支持C++ 11或更新标准的编译器,则可变参数模板不可用.Varargs是.
如果需要编译防火墙.即你需要从头部隐藏函数的实现,然后variadic模板不是一个选项.Varargs是.
在内存受限系统(嵌入式)上,模板生成的不同函数可能会引入太多膨胀.也就是说,这样的系统通常也是实时的,在这种情况下,由于分支和堆栈使用,varargs也可能是不可接受的.
bol*_*lov 14
我想补充@ user2079303的优秀答案
varargs也用于一些元编程(例如用SFINAE实现的特性),因为它们在重载决策上被认为是最后的属性.
假设我们想要实现一个特征来检测一个类是否可以从某些类型构造(类似于std :: is_constructible:
一个简化的现代实现将是这样的(它不是唯一的方式:正如所指出的,void_t也可用于实现特性,很快(2020?)我们将不需要任何这些噱头,因为概念正在与他们的方式require作为一等公民的条款):
template <class T, class... Args> struct Is_constructible {
template <class... Params>
static auto test(Params... params) -> decltype(T{params...}, std::true_type{});
static auto test(...) -> std::false_type;
static constexpr bool value = decltype(test(std::declval<Args>()...))::value;
};
Run Code Online (Sandbox Code Playgroud)
这是因为SFINAE:在实例化时test,如果语义由于某些依赖名称而无效,那么这不是硬错误,而是忽略了重载.
如果你想进一步了解traits技巧及其实现方式和工作原理,你可以进一步阅读:sfinae idiom,成员探测器成语,enable_if idiom.
因此,对于X只能从2个整数构造的类型:
struct X { X(int, int) {}; };
Run Code Online (Sandbox Code Playgroud)
我们得到这些结果:
Is_constructible<X, int, int>::value // true
Is_constructible<X, int>::value; // false
Run Code Online (Sandbox Code Playgroud)
现在的问题是我们是否可以使用可变参数模板替换varargs测试:
template <class T, class... Args> struct Is_constructible_broken {
template <class... Params>
static auto test(Params... params) -> decltype(T{params...}, std::true_type{});
template <class... Params>
static auto test(Params...) -> std::false_type;
static constexpr bool value = decltype(test(std::declval<Args>()...))::value;
};
Run Code Online (Sandbox Code Playgroud)
答案是否定的(至少不是直接替代).当我们实例化时
Is_constructible_broken<X, int, int>::value
Run Code Online (Sandbox Code Playgroud)
我们收到一个错误:
错误:重载'
test(int, int)'的调用是不明确的
因为两个重载都是可行的,并且在重载决策中都具有相同的"等级".使用varargs的第一个实现是有效的,因为即使两个重载都可行,可变参数模板也优于vararg模板.
事实证明,您实际上可以使用可变参数模板.诀窍是添加一个人工参数,test这是第一次重载的完美匹配和第二次重载的转换:
struct overload_low_priority{};
struct overload_high_priority : overload_low_priority {};
template <class T, class... Args> struct Is_constructible2 {
template <class... Params>
static auto test(overload_high_priority, Params... params)
-> decltype(T{params...}, std::true_type{});
template <class... Params>
static auto test(overload_low_priority, Params...) -> std::false_type;
static constexpr bool value
= decltype(test(overload_high_priority{}, std::declval<Args>()...))::value;
};
Run Code Online (Sandbox Code Playgroud)
但我认为在这种情况下varargs更清楚.
vararg 允许使用__attribute__ format. 例如
void debug(const char *fmt, ...) __attribute__((format(printf, 1, 2)));
void f(float value)
{
debug("value = %d\n", value); // <- will show warning.
}
Run Code Online (Sandbox Code Playgroud)
不幸的是,这无法使用可变参数模板来实现。
编辑:正如 Vladimir 指出的,我忘了提及这__attribute__ format不是标准的一部分,但 GCC 和 Clang 都支持它(但 Visual Studio 不支持)。有关更多详细信息,请参阅:https://gcc.gnu.org/onlinedocs/gcc/Common-Function-Attributes.html#Common-Function-Attributes
| 归档时间: |
|
| 查看次数: |
1536 次 |
| 最近记录: |