I'm currently implementing a simple stack in c++17, which has to have a toString-Method, that can deal among other types with std::vector as the template type.
My original problem was, that std::to_string can't accept vector's to I added a specialized implementation for vector's on top of my normal implementation:
template <class T> std::string SweCpp::Stack<T>::toString()
{
std::string result = "SweCpp::Stack[";
for (int a = 0; a < top + 1; a++)
{
T element = st[a];
result += std::to_string(element);
if (a != top) {
result += ", ";
}
}
result += "]";
return result;
}
template <> std::string SweCpp::Stack<std::vector<double>>::toString() {
std::string result = "SweCpp::Stack[";
for (int a = 0; a < top + 1; a++)
{
std::vector<double> element = st[a];
std::string vecAsString = "Vector{";
for (double value : element) {
vecAsString += std::to_string(value) + ",";
}
vecAsString += "}";
result += vecAsString;
if (a != top) {
result += ", ";
}
}
result += "]";
return result;
}
The idea is to call to_string for every element of the vectors, and build a string like that. The problem is, that I can't figure out, how to make the double arbitrary. How can I implement it, so that I can pass any type of vector, e.g. std::vector<int> and std::vector<std::string>?
Something along these lines, perhaps:
template <typename T>
std::string MyToString(const T& val) {
return std::to_string(val);
}
template <typename T>
std::string MyToString(const std::vector<T>& vec) {
std::string vecAsString = "Vector{";
for (const auto& value : vec) {
vecAsString += MyToString(value) + ",";
}
vecAsString += "}";
return vecAsString;
}
Now implement Stack<T>::toString() as in your first example, but call MyToString in place of std::to_string
Related
I think I'm facing something that I imagine is a quite common problem here.
I'd like to write a function that would be able to accept both a container (let's say std::vector) of objects, and a container of pointers to those objects.
What would be the proper way to do so?
Right now, I'm thinking
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);
}
But it doesn't seem quite right, does it?
Consider the standard algorithm library where the problem you see has a solution.
Most algorithms have some default behavior but often allow you to customize that behavior via functor parameters.
For your specific case the algorithm of choice is std::accumulate.
Because this algorithm already exists I can restrict to a rather simplified illustration here:
#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 is a functor that adds two values. Because the return type may differ from the vectors element type an additional template parameter R is used. Similar to std::accumulate this is deduced from the initial value passed as parameter. When adding int the default std::plus<> is fine. When adding integers pointed to by pointers, the functor can add the accumulator with the dereferenced vector element. As already mentioned this is just a simple toy example. In the above link you can find a possible implementation of std::accumulate (which uses iterators rather than the container directly).
With C++20 (or another ranges library), you can easily add or remove pointerness
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; });
}
Or
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; });
}
You can make a function template, which behaves differently for pointer and non-pointer:
#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
You can move almost everything out of the if constexpr to reduce code duplication:
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
Based on #mch solution:
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;
}
Much cleaner and more efficient solution using std::invoke:
std::array<double, 3> centroid(const std::vector<T> & particles)
{
if (particles.empty())
return {0, 0, 0};
std::array<double, 3> cumsum{0.0, 0.0, 0.0};
for (auto && p : particles)
{
cumsum[0] += std::invoke(&topology::Particle::getX, p);
cumsum[1] += std::invoke(&topology::Particle::getY, p);
cumsum[2] += std::invoke(&topology::Particle::getZ, p);
}
double f = 1.0 / particles.size();
cumsum[0] *= f;
cumsum[1] *= f;
cumsum[2] *= f;
return cumsum;
}
I am trying to generate all arrangements of strings in a vector. For example, for
vector<string> vs = { "a", "b", "c"};
I wrote the following code:
do{
for (string s : vs)
cout << s << " ";
cout << endl;
} while (std::next_permutation(vs.begin(), vs.end()));
My output is:
a b c
a c b
b a c
b c a
c a b
c b a
but, I am missing the combinations like
a
a b
b a
c
etc..
I would like to modify my code so that includes these arrangements as well. How to do it? Thanks!
Your example shows that you want to not only output each subset of your input (the Power set) but also all permutations of each set.
I am not aware of a particular term used for this, but OEIS A000522 calls these "arrangements".
To get what you need, you have to essentially combine your code with Jarod's partial answer (or any of the other power set implementations you can find around here):
void outputAllPermutations(std::vector<std::string> input)
{
// assert(std::is_sorted(input.begin(), input.end()));
do
{
for (std::string s : input)
std::cout << s << " ";
std::cout << std::endl;
} while (std::next_permutation(input.begin(), input.end()));
}
bool isBitSet(unsigned bitset, std::size_t i)
{
return (bitset & (1 << i)) != 0;
}
void outputAllArrangements(const std::vector<std::string>& input)
{
// assert(std::is_sorted(input.begin(), input.end()));
// assert(input.size() < std::sizeof(unsigned) * 8);
unsigned bitset = 0;
std::vector<std::string> subset{};
subset.reserve(input.size());
for (unsigned bitset = 0; bitset < (1 << input.size()); ++bitset)
{
subset.clear();
for (std::size_t i = 0; i != input.size(); ++i)
if (isBitSet(bitset, i))
subset.push_back(input[i]);
outputAllPermutations(subset);
}
}
Demo including example output
I used an unsigned instead of std::vector<bool> as I find the overall incrementation logic much easier to reason about that way. This theoretically "limits" the code to inputs smaller than 32 strings (or 64, depending on platform), but seeing as input length 22 would already take thousands of years to output at 1 CPU cycle per output I am comfortable with that.
You might implement Power set with:
bool increase(std::vector<bool>& bs)
{
for (std::size_t i = 0; i != bs.size(); ++i) {
bs[i] = !bs[i];
if (bs[i] == true) {
return true;
}
}
return false; // overflow
}
template <typename T>
void PowerSet(const std::vector<T>& v)
{
std::vector<bool> bitset(v.size());
do {
for (std::size_t i = 0; i != v.size(); ++i) {
if (bitset[i]) {
std::cout << v[i] << " ";
}
}
std::cout << std::endl;
} while (increase(bitset));
}
Demo
Then do permutation of each set, something like:
bool increase(std::vector<bool>& bs)
{
for (std::size_t i = 0; i != bs.size(); ++i) {
bs[i] = !bs[i];
if (bs[i] == true) {
return true;
}
}
return false; // overflow
}
template <typename T, typename F>
void PowerSet(const std::vector<T>& v, F f)
{
std::vector<bool> bitset(v.size());
do {
f(v, bitset);
} while (increase(bitset));
}
template <typename T, typename F>
void AllArrangements(const std::vector<T>& v, F f)
{
PowerSet(v, [f](const std::vector<T>& v, const std::vector<bool>& bitset){
std::vector<T> toPermute;
for (std::size_t i = 0; i != v.size(); ++i) {
if (bitset[i]) {
toPermute.push_back(v[i]);
}
}
do {
f(toPermute);
} while (std::next_permutation(toPermute.begin(), toPermute.end()));
});
}
Demo
I have problem to split a string vector to smaller integer vector\array. My input vector data looks like:
std::vector<std::string> v(2);
v[0] = "0 14 150";
v[1] = "1 2 220";
//...
I know one solution, to make three arrays and to use sstream to convert data to integer. But i want to avoid making "spaghetti" code.
Thank you,
Peter.
I found a split function at stackoverflow some time ago. Unfortunatly, I cannot post the link anymore.
void split(const std::string & str, std::vector<std::string>& cont, const std::string & delims)
{
std::size_t current, previous = 0;
current = str.find_first_of(delims);
while (current != std::string::npos)
{
cont.push_back(std::move(str.substr(previous, current - previous)));
previous = current + 1;
current = str.find_first_of(delims, previous);
}
cont.push_back(std::move(str.substr(previous, current - previous)));
}
I will need delimiter in your strings (seems to be backspace in your case) and call the function on each element of your string vector:
int main()
{
std::vector<std::string> vec{ "0 14 150","1 2 220" };
std::vector<std::vector<int>> intVec(3,std::vector<int>(vec.size()));
for (int i = 0; i < vec.size(); i++)
{
std::vector<std::string> singleStr;
split(vec[i], singleStr, " ");
for (int j=0; j < singleStr.size();j++)
intVec[j][i] = (std::stoi(singleStr[j]));
}
system("pause");
}
A more generic solution could look like this. You can add further types to BasicVariant
#include <string>
#include <vector>
class BasicVariant
{
private:
std::string str;
public:
BasicVariant(const std::string& _str) :str(_str) {}
BasicVariant(int value) :str(std::to_string(value)) {}
BasicVariant(double value) :str(std::to_string(value)) {}
inline int toInt()const { return *this; }
inline double toDouble()const { return *this; }
inline std::string toString()const { return *this; }
inline bool toBool()const { return toDouble(); }
inline operator int()const { return std::stoi(str); }
inline operator double()const { return std::stof(str); }
inline operator std::string()const { return str; }
inline operator bool()const { return toDouble(); }
};
template<typename T>
void split(const std::string& str, std::vector<T>& sink, const std::string& delims)
{
std::size_t current, previous = 0;
current = str.find_first_of(delims);
while (current != std::string::npos)
{
sink.push_back(std::move(BasicVariant(str.substr(previous, current - previous))));
previous = current + 1;
current = str.find_first_of(delims, previous);
}
sink.push_back(std::move(BasicVariant(str.substr(previous, current - previous))));
}
int main()
{
std::vector<std::string> vec{ "0 14 150","1 2 220" };
std::vector<std::vector<int>> intVec(3, std::vector<int>(vec.size()));
for (int i = 0; i < vec.size(); i++)
{
std::vector<int> row;
split(vec[i], row, " ");
for (int j = 0; j < row.size(); j++)
intVec[j][i] = row[j];
}
system("pause");
}
Edit: I removed a verbose transposing function.
I assume that you want to convert std::vector<std::string> to a 2D matrix std::vector<std::vector<int>>.
For instance, for your example, the desired result is assumed to be arr1 = {0,1,...}, arr2 = {14,2,...} and arr3 = {150,220,...}.
First,
We can use std::istream_iterator to extract integers from strings.
We can also apply the range constructor to create a std::vector<int> corresponding to each string.
So the following function would work for you and it does not seem to be a spaghetti code at least to me.
First, this function extract two integer arrays {0,14,150,...} and {1,2,220,...} as matrices from a passed string vector v.
Since a default constructed std::istream_iterator is an end-of-stream iterator, each range constructor reads each string until it fails to read the next value.
And finally, transposed one is returned:
#include <vector>
#include <string>
#include <sstream>
#include <iterator>
template <typename T>
auto extractNumbers(const std::vector<std::string>& v)
{
std::vector<std::vector<T>> extracted;
extracted.reserve(v.size());
for(auto& s : v)
{
std::stringstream ss(s);
std::istream_iterator<T> begin(ss), end; //defaulted end-of-stream iterator.
extracted.emplace_back(begin, end);
}
// this also validates following access to extracted[0].
if(extracted.empty()){
return extracted;
}
decltype(extracted) transposed(extracted[0].size());
for(std::size_t i=0; i<transposed.size(); ++i){
for(std::size_t j=0; j<extracted.size(); ++j){
transposed.at(i).push_back(std::move(extracted.at(j).at(i)));
}
}
return transposed;
}
Then you can extract integers from a string vector as follows:
DEMO
std::vector<std::string> v(n);
v[0] = "0 14 150";
v[1] = "1 2 220";
...
v[n-1] = "...";
auto matrix = extractNumbers<int>(v);
where matrix[0] is arr1, matrix[1] is arr2, and so on.
We can also quickly get internal pointers of them by auto arr1 = std::move(matrix[0]);.
We have here some misunderstands.
Output of my program should have three arrays/vectors.
The output looks like:
arr1| arr1| arr3
0 | 14 | 150
1 | 2 | 220
2 | 4 | 130
template< typename T >
double GetAverage(T tArray[], int nElements)
{
T tSum = T(); // tSum = 0
for (int nIndex = 0; nIndex < nElements; ++nIndex)
{
tSum += tArray[nIndex];
}
// convert T to double
return double(tSum) / nElements;
};
template <typename T>
class pair {
public:
T a;
T b;
pair () {
a=T(0);
b=T(0);
} ;
pair (T a1, T b1) {
a=a1;
b=b1;
};
pair operator += (pair other_pair) {
return pair(a+other_pair.a, b+other_pair.b);
}
operator double() {
return double(a)+ double(b);
}
};
int main(void)
{
pair<int > p1[1];
p1[0]=pair<int >(3,4);
std::cout<< GetAverage <pair <int >>(p1,1) <<"\n";
}
I can't understand why it prints 0 instead of 3.5.
When I copy code from C++ -- How to overload operator+=? all went fine. But I can't understand where I have made
a mistake
pair operator += (pair other_pair) {
return pair(a+other_pair.a, b+other_pair.b);
}
should be
pair &operator += (const pair &other_pair) {
a += other_pair.a;
b += other_pair.b;
return *this;
}
You need to modify the members of this and return a reference to *this, instead of a new object.
It is also a good idea to pass other_pair as a const reference instead of by value.
I have the following overloaded functions:
float myFunc(Vector2D vec) {
Temp2D temp;
for (int i = 0; i < 10; i++) {
temp += computeTemp(vec, i);
}
return temp.compute_a_float();
}
float myFunc(Vector3D vec) {
Temp3D temp;
for (int i = 0; i < 10; i++) {
temp += computeTemp(vec, i);
}
return temp.compute_a_float();
}
float myFunc(Vector4D vec) {
Temp4D temp;
for (int i = 0; i < 10; i++) {
temp += computeTemp(vec, i);
}
return temp.compute_a_float();
}
where computeTemp is also overloaded for Vector2D, Vector3D, Vector4D:
Temp2D computeTemp(Vector2D, int);
Temp3D computeTemp(Vector3D, int);
Temp4D computeTemp(Vector4D, int);
To avoid code duplication, I have come up with the idea to add a layer of abstraction:
template<typename T0, typename T1>
float myFunc(T0 vec) {
T1 temp;
for (int i = 0; i < 10; i++) {
temp += computeTemp(vec, i);
}
return temp.compute_a_float();
}
float myFunc(Vector2D vec) {
return myFunc<Vector2D, Temp2D>(vec);
}
float myFunc(Vector3D vec) {
return myFunc<Vector3D, Temp3D>(vec);
}
float myFunc(Vector4D vec) {
return myFunc<Vector4D, Temp4D>(vec);
}
However, I want to know if it is possible to avoid an additional layer of abstraction and directly decide the type of variable temp in myFunc.
directly decide the type of variable temp in myFunc.
You can use decltype to determine the type, e.g.
template<typename T0>
float myFunc(T0 vec) {
decltype(computeTemp(vec, 0)) temp;
for (int i = 0; i < 10; i++) {
temp += computeTemp(vec, i);
}
return temp.compute_a_float();
}
BTW,
1. Note that if computeTemp returns by reference instead of return-by-value, the result type of decltype would also be reference (to lvalue or rvalue, depending on how computeTemp returns); you might need to use std::remove_reference with decltype to get the type you want.
2. The expression used for decltype belongs to unevaluated expressions:
The operands of the four operators typeid, sizeof, noexcept, and decltype (since C++11) are expressions that are not evaluated (unless they are polymorphic glvalues and are the operands of typeid), since these operators only query the compile-time properties of their operands. Thus, std::size_t n = sizeof(std::cout << 42); does not perform console output.
Or using auto instead of decltype()
template <typename VT>
float myFunc(VT vec) {
auto temp = computeTemp(vec, 0);
for (int i = 1; i < 10; i++) {
temp += computeTemp(vec, i);
}
return temp.compute_a_float();
}
This starting from C++11 (same limit for decltype()).
For C++98, the best I can imagine is the creation of a custom type traits to select the temp type.
Something like [caution: code not tested]
template <typename>
struct tempType;
template <> struct tempType<Vector2D> { typedef Temp2D type; };
template <> struct tempType<Vector3D> { typedef Temp3D type; };
template <> struct tempType<Vector4D> { typedef Temp4D type; };
template <typename VT>
float myFunc(VT vec) {
typename tempType<VT>::type temp;
for (int i = 0; i < 10; i++) {
temp += computeTemp(vec, i);
}
return temp.compute_a_float();
}