我想我正面臨著一些我認為在這里很常見的問題。我想撰寫一個函式,該函式既可以接受物件容器(比如說std::vector
),又可以接受指向這些物件的指標容器。
這樣做的正確方法是什么?
此刻,我在想
int sum(std::vector<int *> v)
{
int s = 0;
for (int * i : v) s = *i;
return s;
}
int sum(std::vector<int> v)
{
std::vector<int *> vp;
for (size_t i = 0; i < v.size(); i)
vp[i] = &v[i];
return sum(vp);
}
但這似乎不太正確,不是嗎?
uj5u.com熱心網友回復:
考慮標準演算法庫,您看到的問題有解決方案。
大多數演算法都有一些默認行為,但通常允許您通過函子引數自定義該行為。
對于您的具體情況,選擇的演算法是std::accumulate
.
因為這個演算法已經存在,我可以在這里限制為一個相當簡化的說明:
#include <iostream>
#include <functional>
template <typename T,typename R,typename F = std::plus<>>
R sum(const std::vector<T>& v,R init,F f = std::plus<>{})
{
for (auto& e : v) init = f(init,e);
return init;
}
int main() {
std::vector<int> x{1,2,3,4};
std::vector<int*> y;
for (auto& e : x ) y.push_back(&e);
std::cout << sum(x,0) << "\n";
std::cout << sum(y,0,[](auto a, auto b) {return a *b;});
}
std::plus
是一個將兩個值相加的函子。因為回傳型別可能與向量元素型別不同,所以使用了額外的模板引數R
。與std::accumulate
此類似的是從作為引數傳遞的初始值推匯出來的。添加int
默認值時std::plus<>
很好。當添加指標指向的整數時,仿函式可以將累加器與取消參考的向量元素相加。如前所述,這只是一個簡單的玩具示例。在上面的鏈接中,您可以找到一個可能的實作std::accumulate
(它使用迭代器而不是直接使用容器)。
uj5u.com熱心網友回復:
使用 C 20(或其他范圍庫),您可以輕松添加或洗掉指標
template <std::ranges::range R, typename T>
concept range_of = requires std::same<std::ranges::range_value_t<R>, T>;
template <range_of<int *> IntPointers>
int sum_pointers(IntPointers int_pointers)
{
int result = 0;
for (int * p : int_pointers) result = *p;
return result;
}
void call_adding_pointer()
{
std::vector<int> v;
sum_pointers(v | std::ranges::views::transform([](int & i){ return &i; });
}
或者
template <range_of<int> Ints>
int sum(Ints ints)
{
int result = 0;
for (int i : ints) result = i;
return result;
}
void call_removing_pointer()
{
std::vector<int *> v;
sum(v | std::ranges::views::transform([](int * p){ return *p; });
}
uj5u.com熱心網友回復:
您可以制作一個函式模板,它對指標和非指標的行為不同:
#include <iostream>
#include <vector>
using namespace std;
template <class T>
auto sum(const std::vector<T> &vec)
{
if constexpr (std::is_pointer_v<T>)
{
typename std::remove_pointer<T>::type sum = 0;
for (const auto & value : vec) sum = *value;
return sum;
}
if constexpr (!std::is_pointer_v<T>)
{
T sum = 0;
for (const auto & value : vec) sum = value;
return sum;
}
}
int main(){
std::vector<int> a{3, 4, 5, 8, 10};
std::vector<int*> b{&a[0], &a[1], &a[2], &a[3], &a[4]};
cout << sum(a) << endl;
cout << sum(b) << endl;
}
https://godbolt.org/z/sch3KovaK
您可以將幾乎所有內容移出if constexpr
以減少代碼重復:
template <class T>
auto sum(const std::vector<T> &vec)
{
typename std::remove_pointer<T>::type sum = 0;
for (const auto & value : vec)
{
if constexpr (std::is_pointer_v<T>)
sum = *value;
if constexpr (!std::is_pointer_v<T>)
sum = value;
}
return sum;
}
https://godbolt.org/z/rvqK89sEK
uj5u.com熱心網友回復:
基于@mch 解決方案,這就是我想出的
template<typename T>
std::array<double, 3> center(const std::vector<T> & particles)
{
if (particles.empty())
return {0, 0, 0};
std::array<double, 3> cumsum = {0, 0, 0};
if constexpr (std::is_pointer_v<T>)
{
for (const auto p : particles)
{
cumsum[0] = p->getX();
cumsum[1] = p->getY();
cumsum[2] = p->getZ();
}
}
if constexpr (not std::is_pointer_v<T>)
{
for (const auto p : particles)
{
cumsum[0] = p.getX();
cumsum[1] = p.getY();
cumsum[2] = p.getZ();
}
}
double f = 1.0 / particles.size();
cumsum[0] *= f;
cumsum[1] *= f;
cumsum[2] *= f;
return cumsum;
}
@463035818_is_not_a_number:我肯定會對你如何使用仿函式函式來做這件事感興趣。
轉載請註明出處,本文鏈接:https://www.uj5u.com/ruanti/496574.html