为什么可变参数函数不适用于模板
Why do variadic functions not work with templates
我想写一个函数来比较几个值并检查哪个值最小。我想将其实现为可变参数函数模板。我知道自 C++11 以来有一个用于此目的的功能,但由于目前我无法使用它的原因。所以我尝试使用<cstdarg>
库,但偶然发现了一些问题。出于某种原因,当我将该函数用作模板时,参数的偏移量计算错误。如果我使用固定类型显式实现该函数,则没有问题。
我的代码:
#include <cstdarg>
#include <iostream>
#include <limits>
template <typename T>
T smallestOf(const int count, const T val1, ... ) { /* I use val1 to determine the template type */
va_list args;
va_start(args, val1);
T smallestVal = std::numeric_limits<T>::max();
for(int i = 0; i < count; i++) {
T nextVal = va_arg(args, T);
std::cout << "nextVal: " << nextVal << std::endl;
if(nextVal < smallestVal) smallestVal = nextVal;
}
va_end(args);
return smallestVal;
}
int main() {
std::cout << "Smallest value: " << smallestOf(3, 10, 20, 30) << std::endl;
}
产生以下输出:
nextVal: 20
nextVal: 30
nextVal: 4217000
Smallest value: 20
看起来函数会读取其内存,因为偏移量是错误的。为什么?
T smallestOf(const int count, const T val1, ... )
当你这样打电话时:smallestOf(3, 10, 20, 30)
varargs20 30
(因为10
是val1
(。 所以你需要count - 1
.
还强烈建议:不要使用varargs。使用可变参数模板或std::initializer_list
您说您无权访问 C++11,所以不幸的是,您既无法访问可变参数模板,也无法访问初始值设定项列表。
好吧,这是我给你的礼物:
template <class T> T min(T e1) { return e1; }
template <class T> T min(T e1, T e2) { return e1 < e2 ? e1: e2; }
template <class T> T min(T e1, T e2, T e3) { return min(e1, min(e2, e3)); }
template <class T> T min(T e1, T e2, T e3, T e4) { return min(e1, min(e2, e3, e4)); }
template <class T> T min(T e1, T e2, T e3, T e4, T e5) { return min(e1, min(e2, e3, e4, e5)); }
template <class T> T min(T e1, T e2, T e3, T e4, T e5, T e6) { return min(e1, min(e2, e3, e4, e5, e6)); }
template <class T> T min(T e1, T e2, T e3, T e4, T e5, T e6, T e7) { return min(e1, min(e2, e3, e4, e5, e6, e7)); }
template <class T> T min(T e1, T e2, T e3, T e4, T e5, T e6, T e7, T e8) { return min(e1, min(e2, e3, e4, e5, e6, e7, e8)); }
template <class T> T min(T e1, T e2, T e3, T e4, T e5, T e6, T e7, T e8, T e9) { return min(e1, min(e2, e3, e4, e5, e6, e7, e8, e9)); }
template <class T> T min(T e1, T e2, T e3, T e4, T e5, T e6, T e7, T e8, T e9, T e10) { return min(e1, min(e2, e3, e4, e5, e6, e7, e8, e9, e10)); }
您可能会想说这是次优的,或者您可以对调用进行分组以减少调用,但任何像样的编译器都会为您内联和优化所有这些调用。clang
和gcc
都使用 10 个参数编译min<int,....>
,只有无分支mov
cmp
和cmov
指令。
刚刚注意到没有 c++11 可用的评论,但由于我刚刚编写了它,这里有一个用 c++17 编写的可变参数解决方案的示例。
也许将来会有用。
#include <iostream>
#include <utility>
#include <type_traits>
template<class T, class...Rest>
auto smallestOf(T const& val1, Rest const&...rest)
-> std::enable_if_t<std::is_same_v<std::common_type_t<T, Rest...>, T>, T const&>
{
auto* current = std::addressof(val1);
if constexpr (sizeof...(Rest) > 0)
{
auto check = [](T const* x, T const* y)
{
return std::addressof(std::min(*x, *y));
};
((current = check(current, std::addressof(rest))),...);
}
return *current;
}
int main() {
std::cout << "Smallest value: " << smallestOf(10) << std::endl;
std::cout << "Smallest value: " << smallestOf(20, 10) << std::endl;
std::cout << "Smallest value: " << smallestOf(30, 10, 20) << std::endl;
std::cout << "Smallest value: " << smallestOf(30, 10, 40, 20) << std::endl;
}
http://coliru.stacked-crooked.com/a/600a91f1678763b2
相关文章:
- OpenGL - 在 NDC 中计算位置适用于着色器,但不适用于'regular'程序
- 使用模板参数重载C++方法:如何使其适用于模板的子类?
- 如何修复我的最大公约数代码?它适用于除零和零以外的所有数字
- 选择排序C++(已修改)并非适用于所有情况
- 无法让"std::enable_if"适用于无作用域枚举
- 请找出我的代码中的错误,它在提交得到错误答案的同时仍然适用于我的所有测试用例
- 确定夏令时是否适用于特定日期
- 是否有一种 STL 算法可以最后找到,但它也适用于指针?
- 十进制到二进制的实现不能完全适用于我大学的检查器。问题或提示可能是什么
- 使用程序集嵌入数据时"Undefined reference"错误,使用适用于窗口的 mingw-w64 编译(COFF 而不是 ELF)
- 为什么 std::vector 适用于类定义中的不完整类型?
- 为什么哈希<常量字符*>适用于字符串而不是字符串变量?
- Lambda适用于最新的Visual Studio,但在其他地方不起作用
- 我该如何文档文档以使文档适用于类成员而不是匿名类型
- 计算 c# 中二进制文件符号的频率不起作用,但适用于等效的 c++ 代码
- 为什么 fstream.open(文件名) 适用于文字而不是生成的字符串?
- 模板重载和 SFINAE 仅适用于函数而不是类
- 为什么链接器不抱怨多个函数定义(仅适用于模板化函数)
- 我可以使用' == '来比较两个向量吗?我试过了,似乎工作正常。但我不知道它是否适用于更复杂的情况
- 延长临时的生命周期,适用于块范围的聚合,但不是通过"新";为什么?