问题
I want to create a function that get vector<int>
run over all his elements and "sum" them according to specific operator I chose .
For example , v1 = [3,6,7]
so I could calculate by this function - 3+6+7
of 3-6-7
of 3*6*7
etc ..
For this I did -
#include <iostream>
#include <vector>
using namespace std;
#define OPERATOR(X,Y,OP) X #OP Y
template<T>
int allVectorWithOperator(vector<int> &myVector, T) {
vector<int>::iterator it;
vector<int>::iterator oneBeforeFinal;
oneBeforeFinal = myVector.end();
oneBeforeFinal -= 2;
int sum = 0;
for (it = myVector.begin(); it <= oneBeforeFinal; it++) {
sum = OPERATOR(*(it),*(it+1),T);
}
return sum;
}
int main() {
vector<int> myVector;
myVector.push_back(3);
myVector.push_back(6);
myVector.push_back(7);
cout << "run over all the vector with * is :" << allVectorWithOperator(myVector,*)<<endl;
// here I want to get 3*6*7
}
I don't control very well in such cases of template so as you can see this code doesn't work, but I think you understand what is my goal. How can I fix it to work fine?
Edit:
according the 2 answer I got I changed the code section to -
#include <iostream>
#include <vector>
#include <numeric>
using namespace std;
template<typename T>
int allVectorWhitOperator(vector<int> &myVector, const T& func) {
int sum = std::accumulate(myVector.begin(), myVector.end(), 1, func);
return sum;
}
int main() {
vector<int> myVector;
myVector.push_back(3);
myVector.push_back(4);
myVector.push_back(6);
cout << "accumulate the vector with * is :"
<< allVectorWhitOperator(myVector, std::multiplies<int>()) << endl;
}
And it work fine ! indeed I got accumulate the vector with * is :72
回答1:
This is basically just std::accumulate. Assuming the vector is not empty, you could rewrite the function as:
template <typename C, typename F>
typename C::value_type fold(const C& container, const F& function) {
typename C::iterator cur = container.begin();
typename C::value_type init = *cur++;
return std::accumulate(cur, container.end(), init, function);
}
...
int sum = fold(myVector, std::plus<int>());
int difference = fold(myVector, std::minus<int>());
int product = fold(myVector, std::multiplies<int>());
Now, about your implementation:
As shown in the example above, to declare a type parameter in the template, you need to have the
typename
orclass
keyword:template <typename T> int allVectorWithOperator( ... )
A lone
*
won't be a valid syntax. But C++ provides a lot of "function objects" which serve wraps these operators so that you could use them with the function notation. For example,std::multiplies<int> f; // f is a now function that multiplies 2 numbers int product = f(5, 7); // p == 35;
so you could write:
template<typename T> int allVectorWithOperator(vector<int> &myVector, T func) { .... for (it = myVector.begin(); it != oneBeforeFinal; ++ it) { sum = func(*it, *(it+1)); } }
Also, some minor points: (1) Usually we compare iterators with
!=
instead of<=
, because many iterators don't support the<=
operator, (2)++it
is more efficient thanit++
in general.Macros and templates are processed in different stages. In particular, you can't pass a template or function parameter to a macro, because all macros are already evaluated when templates are considered. To achieve your syntax, the whole
allVectorWithOperator
must be written as a macro, e.g. (assuming C++11 can be used):#define allVectorWithOperator(container, binaryOp) \ ([&]() -> std::remove_reference<decltype(*(container).begin())>::type { \ auto&& c = (container); \ auto cur = c.begin(); \ auto val = *cur++; \ auto end = c.end(); \ while (cur != end) { val binaryOp##= *cur++; } \ return val; \ }())
Yes it's a complete mess, so you should prefer not to use macros if possible. BTW,
#OP
means turning theOP
into a string. You don't really need the#
.
回答2:
The standard library already has the operations in <algorithm>
<numeric>
.
You can use
int sum = std::accumulate(MyVector.begin(), MyVector.end(), 0);
to add up all the elements.
If you want to compute the product (instead of using the default operator+
), you can pass an additional parameter
int product = std::accumulate(MyVector.begin(), MyVector.end(), 1,
std::multiplies<int>());
来源:https://stackoverflow.com/questions/12287768/template-function-with-macro-accumulate-on-vector