I need to write a unit test (gtest) which passes two values from arrays a[] and b[] respectively.
Example:
a[] = {40, 45, 50 ,55, 60}
b[] = {2, 3, 5, 8, 9, 11}
My test case will pass these arrays (a[],b[]) as arguments to a function.
Is there a way I can pass both the arrays into a test case ?
Expecting the arrays are static then you can pass them like the following example shows:
class ArrayTests : public UnitTest_SomeClass,
public testing::WithParamInterface<std::pair<int*, int*>>
{
};
TEST_P(ArrayTests, doSomething)
{
const auto pair = GetParam();
const auto a = pair.first;
const auto b = pair.second;
EXPECT_EQ(4, a[3]);
EXPECT_EQ(6, b[4]);
}
int a[]{ 1,2,3,4 };
int b[]{ 2,3,4,5,6 };
INSTANTIATE_TEST_CASE_P(UnitTest_SomeClass, ArrayTests, testing::Values(std::make_pair(a, b)));
You can now pass different arrays to the test:
int a0[]{ 1,2,3,4 };
int b0[]{ 2,3,4,5,6 };
int a1[]{ 7,8,9,10 };
int b1[]{ 2,3,4,5,6 };
INSTANTIATE_TEST_CASE_P(UnitTest_SomeClass, ArrayTests, testing::Values(std::make_pair(a0, b0), std::make_pair(a1, b1)));
I think it would be easier to use std::vector here for the int arrays, cause you got access to the number of elements. HTH
In case of more than 2 arrays are required.
#include "gtest/gtest.h"
using namespace std;
class MyTest : public testing::TestWithParam<tuple<vector<int>, vector<string>, vector<double>>> {
protected:
virtual void SetUp() {
cout << "{";
}
virtual void TearDown() {
cout << "}" << endl;
}
};
TEST_P(MyTest, TestP1) {
auto [p1, p2, p3] = GetParam();
for (auto v1: p1) cout << v1 << ",";
for (auto v2: p2) cout << v2 << ",";
for (auto v3: p3) cout << v3 << ",";
}
INSTANTIATE_TEST_SUITE_P(ParaGroupName,
MyTest,
testing::Values(
make_tuple(vector<int>{1, 2}, vector<string>{"a1", "b1"}, vector<double>{1., 2.}),
make_tuple(vector<int>{11, 12}, vector<string>{"a2", "b2"}, vector<double>{11., 12.})
)
);
// {1,2,a1,b1,1,2,}
// {11,12,a2,b2,11,12,}
Related
#include <iostream>
#include <vector>
#include <string>
#include <type_traits>
#include <map>
#include <any>
using namespace std;
int func1(int a, int b, int c) {
return a + b + c;
}
int func1Wrapper(map<string, std::any> params)
{
int a = any_cast<int>(params["a"]), b = any_cast<int>(params["b"]), c = any_cast<int>(params["c"]);
return func1(a,b,c);
}
double func2(int a, int b) {
return a * b;
}
double func2Wrapper(map<string, std::any> params)
{
int a = any_cast<int>(params["a"]), b = any_cast<int>(params["b"]);
return func2(a,b);
}
int func3(int a, string b) {
return a + b.length();
}
int func3Wrapper(map<string, std::any> params)
{
int a = any_cast<int>(params["a"]);
string b = any_cast<string>(params["b"]);
return func3(a,b);
}
int func4(int a, vector<int> b) {
int sum = 0;
for (const auto& x : b) sum += x;
return a + sum;
}
int func4Wrapper(map<string, std::any> params)
{
int a = any_cast<int>(params["a"]);
auto b = any_cast<vector<int>>(params["b"]);
return func4(a,b);
}
typedef map<string, vector<map<string, any>>> FeatureMap;
vector<vector<std::any>> executor(map<string, vector<map<string, any>>> featureMap)
{
vector<vector<std::any>> res;
for (auto it=featureMap.begin(); it!=featureMap.end(); it++)
{
vector<std::any> currentRes;
if (it->first=="func1") {
for (auto paramIt=it->second.begin(); paramIt!=it->second.end(); paramIt++)
currentRes.push_back(func1Wrapper(*paramIt));
}
if (it->first=="func2") {
for (auto paramIt=it->second.begin(); paramIt!=it->second.end(); paramIt++)
currentRes.push_back(func2Wrapper(*paramIt));
}
if (it->first=="func3") {
for (auto paramIt=it->second.begin(); paramIt!=it->second.end(); paramIt++)
currentRes.push_back(func3Wrapper(*paramIt));
}
if (it->first=="func4") {
for (auto paramIt=it->second.begin(); paramIt!=it->second.end(); paramIt++)
currentRes.push_back(func4Wrapper(*paramIt));
}
res.push_back(currentRes);
}
return res;
}
int main()
{
FeatureMap fm;
fm["func1"] = { {{"a", 1}, {"b", 2}, {"c", 3}} , {{"a", 3}, {"b", -4}, {"c", 5}} };
fm["func2"] = { {{"a", 2}, {"b", 2}} , {{"a", 3}, {"b", -4}} };
fm["func3"] = { {{"a", 3}, {"b", "hello"s}} , {{"a", 3}, {"b", "123"s}} };
fm["func4"] = { {{"a", 4}, {"b", vector<int>({1,2,3})}}, {{"a", 3}, {"b", vector<int>({3,4,5})}} };
auto res = executor(fm);
auto func1Res = res[0], func2Res = res[1], func3Res = res[2], func4Res = res[3];
cout << any_cast<int>(func1Res[0]) << " " << any_cast<int>(func1Res[1]) << "\n";
cout << any_cast<double>(func2Res[0]) << " " << any_cast<double>(func2Res[1]) << "\n";
cout << any_cast<int>(func3Res[0]) << " " << any_cast<int>(func3Res[1]) << "\n";
cout << any_cast<int>(func4Res[0]) << " " << any_cast<int>(func4Res[1]) << "\n";
return 0;
}
I am converting a Python library to C++, it uses dict() everywhere.
A 1-1 conversion is like the code above: an executor accept a list of function, each function can have different parameter types and length. I store the parameters in a map<string, std::any> params, and for each function I have to manually extract the parameter then manually call the function (like func1Wrapper).
This code is very tedious to use and update. More importantly, it's very slow since there are map and std::any everywhere. I wish to use template to do as much thing as possible at compile time.
Is there anyway to convert the above code to using template? The executor should be able to accept any function with any parameter (different length, different types, ...). Instead of using a map<string, std::any> params, a user must give the function parameters in the correct order.
Edit: if the above is impossible, then what should I use to achieve similar functionality? Basically, the executor should be able to perform:
vector<vector<std::any>> res;
vector<vector<vector<std::any>> param_list;
for (i=0; i<function_list.size(); i++):
{
vector<std::any> currentRes;
for (j=0; j<param_list[i].size(); j++)
currentRes.push_back(function_list[i](param_list[i][j]));
res.push_back(currentRes);
}
while using as much compile-time stuffs as possible.
The executor should be able to accept any function with any parameter (different length, different types, ...).
You can use a combination of perfect forwarding and variadic templates as shown below. In the program shown, the function template forwardToArbitFunc<> accepts any number of function call arguments and forwards each of them to another function(which is also passed as the first argument to the function template).
#include <iostream>
#include<string>
//this function template forwards its arguments to arbitrary function
template<typename T, typename... Ts> void forwardToArbitFunc(T g,Ts&&... xs)
{
g(std::forward<Ts>(xs)...); // forward all xs to g()
}
void func()
{
std::cout<<"parameterless func called"<<std::endl;
}
void func2(int a)
{
std::cout<<"one parameter func2 called"<<std::endl;
}
void func3(std::string a, int b)
{
std::cout<<"two parameter func3 called"<<std::endl;
}
void func4(std::string a, std::string b, float c, double d)
{
std::cout<<"four parameter func4 called"<<std::endl;
}
int main()
{
forwardToArbitFunc(func);
forwardToArbitFunc(func2, 3);
forwardToArbitFunc(func3, "some string", 5);
forwardToArbitFunc(func4, "some string", "another string", 4.4, 5.5);
return 0;
}
Demo
There are tons of answers for sorting a vector of struct in regards to a member variable. That is easy with std::sort and a predicate function, comparing the structs member. Really easy.
But I have a different question. Assume that I have the following struct:
struct Test {
int a{};
int b{};
int toSort{};
};
and a vector of that struct, like for example:
std::vector<Test> tv{ {1,1,9},{2,2,8},{3,3,7},{4,4,6},{5,5,5} };
I do not want to sort the vectors elements, but only the values in the member variable. So the expected output should be equal to:
std::vector<Test> tvSorted{ {1,1,5},{2,2,6},{3,3,7},{4,4,8},{5,5,9} };
I wanted to have the solution to be somehow a generic solution. Then I came up with a (sorry for that) preprocessor-macro-solution. Please see the following example code:
#include <iostream>
#include <vector>
#include <algorithm>
struct Test {
int a{};
int b{};
int toSort{};
};
#define SortSpecial(vec,Struct,Member) \
do { \
std::vector<decltype(Struct::Member)> vt{}; \
std::transform(vec.begin(), vec.end(), std::back_inserter(vt), [](const Struct& s) {return s.Member; }); \
std::sort(vt.begin(), vt.end()); \
std::for_each(vec.begin(), vec.end(), [&vt, i = 0U](Struct & s) mutable {s.Member = vt[i++]; }); \
} while (false)
int main()
{
// Define a vector of struct Test
std::vector<Test> tv{ {1,1,9},{2,2,8},{3,3,7},{4,4,6},{5,5,5} };
for (const Test& t : tv) std::cout << t.a << " " << t.b << " " << t.toSort << "\n";
// Call sort macro
SortSpecial(tv, Test, toSort);
std::cout << "\n\nSorted\n";
for (const Test& t : tv) std::cout << t.a << " " << t.b << " " << t.toSort << "\n";
}
Since macros shouldn't be used in C++, here my questions:
1. Is a solution with the algorithm library possible?
2. Or can this be achieved via templates?
To translate your current solution to a template solution is fairly straight forward.
template <typename T, typename ValueType>
void SpecialSort(std::vector<T>& vec, ValueType T::* mPtr) {
std::vector<ValueType> vt;
std::transform(vec.begin(), vec.end(), std::back_inserter(vt), [&](const T& s) {return s.*mPtr; });
std::sort(vt.begin(), vt.end());
std::for_each(vec.begin(), vec.end(), [&, i = 0U](T& s) mutable {s.*mPtr = vt[i++]; });
}
And we can call it by passing in the vector and a pointer-to-member.
SpecialSort(tv, &Test::toSort);
Somewhow like this (You just need to duplicate, rename and edit the "switchToShort" funtion for the rest of the variables if you want):
#include <iostream>
#include <vector>
struct Test {
int a{};
int b{};
int toSort{};
};
void switchToShort(Test &a, Test &b) {
if (a.toSort > b.toSort) {
int temp = a.toSort;
a.toSort = b.toSort;
b.toSort = temp;
}
}
//void switchToA(Test& a, Test& b) { ... }
//void switchToB(Test& a, Test& b) { ... }
inline void sortMemeberValues(std::vector<Test>& data, void (*funct)(Test&, Test&)) {
for (int i = 0; i < data.size(); i++) {
for (int j = i + 1; j < data.size(); j++) {
(*funct)(data[i], data[j]);
}
}
}
int main() {
std::vector<Test> tv { { 1, 1, 9 }, { 2, 2, 8 }, { 3,3 ,7 }, { 4, 4, 6 }, { 5, 5, 5} };
sortMemeberValues(tv, switchToShort);
//sortMemeberValues(tv, switchToA);
//sortMemeberValues(tv, switchToB);
for (const Test& t : tv) std::cout << t.a << " " << t.b << " " << t.toSort << "\n";
}
With range-v3 (and soon ranges in C++20), you might simply do:
auto r = tv | ranges::view::transform(&Test::toSort);
std::sort(r.begin(), r.end());
Demo
Is there any shortcut method in c++ to output 2d array(i.e. apart from for loop)?
Is there a special function in STL to output it.
Well, since you mentioned STL functions, you could use the std::for_each function with lambda functions to print the 2D array:
#include <iostream>
using namespace std;
int main(int argc, char *argv[]) {
int matrix[3][3] = { {1,2,3},{4,5,6},{7,8,9} };
auto elem_printer = [](int num) { std::cout << num << " "; };
auto row_printer = [&elem_printer](int (&row)[3]) {
std::for_each(std::begin(row),std::end(row),elem_printer);
std::cout << std::endl;
};
std::for_each(std::begin(matrix),std::end(matrix),row_printer);
}
However, this is exactly the same as two for loops, but uglier.
I have this template for streams, which hides away some of the ugliness, and you benefit from it being reusable and it handles multiple dimensions. There is no way to get away without doing the loops somewhere, of course:
template <class Stream, size_t depth>
class Pretty
{
Stream& s;
public:
Pretty(Stream& s): s(s) {}
template <size_t d1, typename T>
Stream& operator <<( T const (&v)[d1])const
{
const char* sep = "{";
for (auto& m : v)
{
s << sep << m;
sep = ", ";
}
s << "}";
return s;
}
template <size_t d1, typename T, size_t d2>
std::ostream& operator <<(T const (&v)[d1][d2])const
{
enum {DENT = 4};
std::string dent (DENT,' ');
std::string indent(depth*DENT,' ');
std::string sep = "{\n" + indent + dent;
for (auto& m : v)
{
s << sep; Pretty<Stream,depth+1>(s) << m;
sep = ",\n" + indent + dent;
}
s << "\n" << indent << "}";
return s;
}
};
class PrettyNext
{};
Pretty<std::ostream,0> operator << (std::ostream& s, const PrettyNext&)
{
return Pretty<std::ostream,0>(s);
}
And usage:
int i [][3][2] = { { {1,2}, {3,4}, {5,6} },{{0}}};
std::cout << "This is a test:\n" << PrettyNext() << i << std::endl;
Output is:
This is a test:
{
{
{1, 2},
{3, 4},
{5, 6}
},
{
{0, 0},
{0, 0},
{0, 0}
}
}
I have been fighting to get this to work directly on std::ostream, but there is a collision with the standard char* handling I can't quite resolve.
Can someone point me, please, if where is some algorithms within STL to compute difference and intersection per one call in manner of unix comm utility?
int main()
{
//For example we have two sets on input
std::set<int>a = { 1 2 3 4 5 };
std::set<int>b = { 3 4 5 6 7 };
std::call_some_func(a, b, ... );
//So as result we need obtain 3 sets
//x1 = {1, 2} // present in a, but absent in b (difference)
//x2 = {3, 4, 5} // present on both sets (intersection)
//x3 = {6, 7} // present in b, but absent in a
}
My current implementation uses 2 calls of 'std::set_difference' and one call of 'std::set_intersection'.
I think this is probably a reasonably efficient implementation:
Features:
a) operates in linear time.
b) works with all ordered container types for input and all iterator types for output.
c) only requires operator< to be defined on the contained type, as per stl algorithms on sorted ranges.
template<class I1, class I2, class I3, class I4, class ITarget1, class ITarget2, class ITarget3>
auto comm(I1 lfirst, I2 llast, I3 rfirst, I4 rlast, ITarget1 lonly, ITarget2 both, ITarget3 ronly)
{
while (lfirst != llast and rfirst != rlast)
{
auto&& l = *lfirst;
auto&& r = *rfirst;
if (l < r) *lonly++ = *lfirst++;
else if (r < l) *ronly++ = *rfirst++;
else *both++ = (++lfirst, *rfirst++);
}
while (lfirst != llast)
*lonly++ = *lfirst++;
while (rfirst != rlast)
*ronly++ = *rfirst++;
}
example:
#include <tuple>
#include <set>
#include <vector>
#include <unordered_set>
#include <iterator>
#include <iostream>
/// #pre l and r are ordered
template<class I1, class I2, class I3, class I4, class ITarget1, class ITarget2, class ITarget3>
auto comm(I1 lfirst, I2 llast, I3 rfirst, I4 rlast, ITarget1 lonly, ITarget2 both, ITarget3 ronly)
{
while (lfirst != llast and rfirst != rlast)
{
auto&& l = *lfirst;
auto&& r = *rfirst;
if (l < r) *lonly++ = *lfirst++;
else if (r < l) *ronly++ = *rfirst++;
else *both++ = (++lfirst, *rfirst++);
}
while (lfirst != llast)
*lonly++ = *lfirst++;
while (rfirst != rlast)
*ronly++ = *rfirst++;
}
int main()
{
//For example we have two sets on input
std::set<int>a = { 1, 2, 3, 4, 5 };
std::set<int>b = { 3, 4, 5, 6, 7 };
std::vector<int> left;
std::set<int> right;
std::unordered_set<int> both;
comm(begin(a), end(a),
begin(b), end(b),
back_inserter(left),
inserter(both, both.end()),
inserter(right, right.end()));
//So as result we need obtain 3 sets
//x1 = {1, 2} // present in a, but absent in b (difference)
//x2 = {3, 4, 5} // present on both sets (intersection)
//x3 = {6, 7} // present in b, but absent in a
std::copy(begin(left), end(left), std::ostream_iterator<int>(std::cout, ", "));
std::cout << std::endl;
std::copy(begin(both), end(both), std::ostream_iterator<int>(std::cout, ", "));
std::cout << std::endl;
std::copy(begin(right), end(right), std::ostream_iterator<int>(std::cout, ", "));
std::cout << std::endl;
}
example output (note that the 'both' target is an unordered set):
1, 2,
5, 3, 4,
6, 7,
There is no single function to do that, you'd have to call the three functions you mentioned, or write something yourself. That being said, here's my attempt, though I'm not sure it's going to be any faster than the three step method you've already described
#include <algorithm>
#include <iostream>
#include <iterator>
#include <set>
template <typename T>
void partition_sets(std::set<T> const& a,
std::set<T> const& b,
std::set<T>& difference_a,
std::set<T>& difference_b,
std::set<T>& intersection)
{
std::set_intersection(begin(a), end(a),
begin(b), end(b),
std::inserter(intersection, intersection.begin()));
std::copy_if(begin(a), end(a), std::inserter(difference_a, difference_a.begin()), [&intersection](int i)
{
return intersection.find(i) == intersection.end();
});
std::copy_if(begin(b), end(b), std::inserter(difference_b, difference_b.begin()), [&intersection](int i)
{
return intersection.find(i) == intersection.end();
});
}
Running your example
int main()
{
//For example we have two sets on input
std::set<int> a = { 1, 2, 3, 4, 5 };
std::set<int> b = { 3, 4, 5, 6, 7 };
std::set<int> x1;
std::set<int> x2;
std::set<int> x3;
partition_sets(a, b, x1, x2, x3);
std::cout << "a - b\n\t";
for (int i : x1)
{
std::cout << i << " ";
}
std::cout << "\n";
std::cout << "b - a\n\t";
for (int i : x2)
{
std::cout << i << " ";
}
std::cout << "\n";
std::cout << "intersection\n\t";
for (int i : x3)
{
std::cout << i << " ";
}
}
produces the output
a - b
1 2
b - a
6 7
intersection
3 4 5
Just write a wrapper for the three calls of the algorithms.
For example
#include <iostream>
#include<tuple>
#include <set>
#include <iterator>
#include <algorithm>
template <class T>
auto comm(const std::set<T> &first, const std::set<T> &second)
{
std::tuple<std::set<T>, std::set<T>, std::set<T>> t;
std::set_difference(first.begin(), first.end(),
second.begin(), second.end(),
std::inserter(std::get<0>(t), std::get<0>(t).begin()));
std::set_intersection(first.begin(), first.end(),
second.begin(), second.end(),
std::inserter(std::get<1>(t), std::get<1>(t).begin()));
std::set_difference(second.begin(), second.end(),
first.begin(), first.end(),
std::inserter(std::get<2>(t), std::get<2>(t).begin()));
return t;
}
int main()
{
std::set<int> a = { 1, 2, 3, 4, 5 };
std::set<int> b = { 3, 4, 5, 6, 7 };
auto t = comm(a, b);
for (auto x : std::get<0>(t)) std::cout << x << ' ';
std::cout << std::endl;
for (auto x : std::get<1>(t)) std::cout << x << ' ';
std::cout << std::endl;
for (auto x : std::get<2>(t)) std::cout << x << ' ';
std::cout << std::endl;
return 0;
}
The program output is
1 2
3 4 5
6 7
I met a question in my work
There is an unordered_map on vector<int> in my c++ class
like this unordered_map < int, vector<int> >
so how could I initialize the nested container so that when I insert a key to the hash table
and the value(vector) will be ten zero ?
You can use list initialization:
std::unordered_map<int, std::vector<int>> m
{ { 2, std::vector<int>(10, 0) }
, { 5, std::vector<int>(10, 0) }
, { 6, std::vector<int>(10, 0) }
, { 9, std::vector<int>(10, 0) }
};
It's very simple:
std::unordered_map<int, std::vector<int>> my_map;
my_map[123] = std::vector<int>{1, 2, 3, 4, 5, 6, 7, 8, 9, 0 };
Now my_map will contain one entry, with the key 123 and data being a vector containing ten entries.
Do not allow users to access the map directly, make them go through an accessor so you can ensure the vector gets populated how you want:
class FooBar
{
public:
// access the map
std::vector<int>& operator[](int n);
private:
std::unordered_map<int, std::vector<int>> map;
};
std::vector<int>& FooBar::operator[](int n)
{
auto iter = map.find(n);
if (iter == map.end()) // index not found, so insert it
iter = map.emplace(n, std::vector<int>(10, 0)).first;
return *iter;
}
According to what you stated in the comments you need a fixed size array.
Here a small example:
#include <array>
#include <unordered_map>
#include <iostream>
int main(int, char const *[])
{
std::unordered_map<int, std::array<int, 10>> the_map;
std::cout << the_map[0][1] << std::endl;
the_map[0][2]++;
std::cout << the_map[0][2] << std::endl;
return 0;
}
Output will be:
0
1
If you want to change the default value you can do something like:
struct my_array : public std::array<int, 10> { my_array() { fill(2); } };
int main(int , char const *[])
{
std::unordered_map<int, my_array> the_map;
std::cout << the_map[0][1] << std::endl;
the_map[0][2]++;
std::cout << the_map[0][2] << std::endl;
return 0;
}
Output:
2
3
Not my favorite choice, but you can do it this way.