在我的可变参数模板中获取 UB 按元素对可变数量的向量求和
Getting UB in my variadic template summing a variable number of vectors element-wise
我正在尝试创建一个函数 AddVector
以元素方式添加(可变)数量的向量。我想我明白了,但是当我得到错误的输出时,我显然没有。我添加了三个双精度向量,每个大小为 5,包含 1+2+1,因此我期望
4 4 4 4 4
我明白了
1.36234e-316 2.0326e-316 4 4 4
哪个明显错误(可能是未初始化的内存?)
我用 CppInsights 查看了翻译后的代码,但看起来也不错。我在这里做错了什么?
我的代码:
#include <vector>
template<typename T>
using Vec = std::vector<T>;
template<typename T>
auto SumAndIncVcIt(T& t) {
return *t++;
}
template<typename T, typename... Args>
auto SumAndIncVcIt(T& t, Args&... args) {
return *t++ + SumAndIncVcIt(args...);
}
#include <tuple>
template<typename... Args>
auto VcBegins(Args... args){
return std::make_tuple(cbegin(args)...);
}
template<typename T, size_t... Is>
auto SumAndIncVcIts_impl(T& t, std::index_sequence<Is...>) {
return SumAndIncVcIt(std::get<Is>(t)...);
}
template<class Tuple>
auto SumAndIncVcIts(Tuple& t) {
return SumAndIncVcIts_impl(t,
std::make_index_sequence<std::tuple_size<Tuple>{}>{}
);
}
template<typename T, typename... Args>
Vec<T> AddVector(Vec<T> const& vt, Vec<Args> const&... vargs){
auto vret = Vec<T>(size(vt));
auto vcIts = VcBegins(vt, vargs...);
auto retIt = begin(vret);
while(retIt != end(vret)){
*retIt++ = SumAndIncVcIts(vcIts);
}
return vret;
}
#include<iostream>
int main() {
constexpr auto size = 5;
Vec<double> a(size, 1.0), b(size, 2.0);
auto c = AddVector(a, b, a);
for(auto const& el : c){
std::cout << el << " ";
}
}
p.s。是的,我应该使用 SFINEA 或概念。
还不确定你的问题出在哪里,你自己发现的:) ...但这就是我用 C++17 和大小实现它的方式:
#include <vector>
#include <algorithm>
template<typename T>
using Vec = std::vector<T>;
template<typename T, typename...Args>
Vec<T> AddVector_impl(Vec<Args> const & ... vecs){
auto sizes = {vecs.size()...};
auto new_size = *std::min_element(sizes.begin(),sizes.end());
Vec<T> res(new_size);
for(std::size_t i=0;i<new_size;++i){
res[i]=(vecs[i]+...);
}
return res;
}
// Ensures at least one vector, also sets its return type.
template<typename T, typename... Args>
Vec<T> AddVector(Vec<T> const& vt, Vec<Args> const&... vargs){
return AddVector_impl<T>(vt,vargs...);
}
#include <iostream>
int main() {
constexpr auto size = 5;
Vec<double> a(size, 1.0), b(size, 2.0);
auto c = AddVector(a, b, a);
for(auto const& el : c){
std::cout << el << " ";
}
}
输出:
4 4 4 4 4
仅迭代器解决方案
#include <vector>
#include <algorithm>
template<typename T>
using Vec = std::vector<T>;
template<typename T, typename...Args>
Vec<T> AddVector_impl(Vec<Args> const & ... vecs){
auto its = std::tuple(vecs.cbegin()...);
auto add_inc = [](auto&... iters){
return ((*iters++) + ... );
};
auto end_check = [&](auto&...iters){
return ((iters!=vecs.cend()) && ...);
};
Vec<T> res;
auto it = std::back_insert_iterator(res);
while(std::apply(end_check,its)){
*it++=std::apply(add_inc,its);
}
return res;
}
template<typename T, typename... Args>
Vec<T> AddVector(Vec<T> const& vt, Vec<Args> const&... vargs){
return AddVector_impl<T>(vt,vargs...);
}
#include <iostream>
int main() {
constexpr auto size = 5;
Vec<double> a(size, 1.0), b(size, 2.0);
auto c = AddVector(a, b, a);
for(auto const& el : c){
std::cout << el << " ";
}
}
自己找的...
template<typename... Args>
auto VcBegins(Args... args){
return std::make_tuple(cbegin(args)...);
}
按值传递,因此向量被复制,我得到无效的迭代器
当然应该
template<typename... Args>
auto VcBegins(Args const&... args){
return std::make_tuple(cbegin(args)...);
}
我正在尝试创建一个函数 AddVector
以元素方式添加(可变)数量的向量。我想我明白了,但是当我得到错误的输出时,我显然没有。我添加了三个双精度向量,每个大小为 5,包含 1+2+1,因此我期望
4 4 4 4 4
我明白了
1.36234e-316 2.0326e-316 4 4 4
哪个明显错误(可能是未初始化的内存?)
我用 CppInsights 查看了翻译后的代码,但看起来也不错。我在这里做错了什么?
我的代码:
#include <vector>
template<typename T>
using Vec = std::vector<T>;
template<typename T>
auto SumAndIncVcIt(T& t) {
return *t++;
}
template<typename T, typename... Args>
auto SumAndIncVcIt(T& t, Args&... args) {
return *t++ + SumAndIncVcIt(args...);
}
#include <tuple>
template<typename... Args>
auto VcBegins(Args... args){
return std::make_tuple(cbegin(args)...);
}
template<typename T, size_t... Is>
auto SumAndIncVcIts_impl(T& t, std::index_sequence<Is...>) {
return SumAndIncVcIt(std::get<Is>(t)...);
}
template<class Tuple>
auto SumAndIncVcIts(Tuple& t) {
return SumAndIncVcIts_impl(t,
std::make_index_sequence<std::tuple_size<Tuple>{}>{}
);
}
template<typename T, typename... Args>
Vec<T> AddVector(Vec<T> const& vt, Vec<Args> const&... vargs){
auto vret = Vec<T>(size(vt));
auto vcIts = VcBegins(vt, vargs...);
auto retIt = begin(vret);
while(retIt != end(vret)){
*retIt++ = SumAndIncVcIts(vcIts);
}
return vret;
}
#include<iostream>
int main() {
constexpr auto size = 5;
Vec<double> a(size, 1.0), b(size, 2.0);
auto c = AddVector(a, b, a);
for(auto const& el : c){
std::cout << el << " ";
}
}
p.s。是的,我应该使用 SFINEA 或概念。
还不确定你的问题出在哪里,你自己发现的:) ...但这就是我用 C++17 和大小实现它的方式:
#include <vector>
#include <algorithm>
template<typename T>
using Vec = std::vector<T>;
template<typename T, typename...Args>
Vec<T> AddVector_impl(Vec<Args> const & ... vecs){
auto sizes = {vecs.size()...};
auto new_size = *std::min_element(sizes.begin(),sizes.end());
Vec<T> res(new_size);
for(std::size_t i=0;i<new_size;++i){
res[i]=(vecs[i]+...);
}
return res;
}
// Ensures at least one vector, also sets its return type.
template<typename T, typename... Args>
Vec<T> AddVector(Vec<T> const& vt, Vec<Args> const&... vargs){
return AddVector_impl<T>(vt,vargs...);
}
#include <iostream>
int main() {
constexpr auto size = 5;
Vec<double> a(size, 1.0), b(size, 2.0);
auto c = AddVector(a, b, a);
for(auto const& el : c){
std::cout << el << " ";
}
}
输出:
4 4 4 4 4
仅迭代器解决方案
#include <vector>
#include <algorithm>
template<typename T>
using Vec = std::vector<T>;
template<typename T, typename...Args>
Vec<T> AddVector_impl(Vec<Args> const & ... vecs){
auto its = std::tuple(vecs.cbegin()...);
auto add_inc = [](auto&... iters){
return ((*iters++) + ... );
};
auto end_check = [&](auto&...iters){
return ((iters!=vecs.cend()) && ...);
};
Vec<T> res;
auto it = std::back_insert_iterator(res);
while(std::apply(end_check,its)){
*it++=std::apply(add_inc,its);
}
return res;
}
template<typename T, typename... Args>
Vec<T> AddVector(Vec<T> const& vt, Vec<Args> const&... vargs){
return AddVector_impl<T>(vt,vargs...);
}
#include <iostream>
int main() {
constexpr auto size = 5;
Vec<double> a(size, 1.0), b(size, 2.0);
auto c = AddVector(a, b, a);
for(auto const& el : c){
std::cout << el << " ";
}
}
自己找的...
template<typename... Args>
auto VcBegins(Args... args){
return std::make_tuple(cbegin(args)...);
}
按值传递,因此向量被复制,我得到无效的迭代器
当然应该
template<typename... Args>
auto VcBegins(Args const&... args){
return std::make_tuple(cbegin(args)...);
}