I decided to implement Python's slice with C++ by myself. I wrote a function which accepts variadic slice_info<int> arguments and returns the slice selection of an n-dimensional array, ndvalarray<T, D>.
I compiled with Visual C++ 2015 and the code is like the following:
template<typename T>
struct slice_info {
T fr, to, step;
slice_info(T i) {
fr = 1; to = i; step = 1;
}
slice_info(std::initializer_list<T> il) {
std::vector<T> l(il);
if (l.size() == 1)
{
fr = 1; step = 1; to = l[0];
}
else if (l.size() == 2) {
fr = l[0]; step = 1; to = l[1];
}
else {
fr = l[0]; step = l[2]; to = l[1];
}
}
slice_info(const slice_info<T> & x) : fr(x.fr), to(x.to), step(x.step) {
}
};
template<typename T, int D>
void slice(const ndvalarray<T, D> & va, slice_info<int>&& s) {
// ndvalarray<T, D> is a n-dimensional array of type T
}
template<typename T, int D, typename ... Args>
void slice(const ndvalarray<T, D> & va, slice_info<int>&& s, Args&& ... args) {
slice(va, std::forward<Args>(args)...);
}
template<typename T, int D>
void slice_work_around(const ndvalarray<T, D> & va, const std::vector<slice_info<int>> & vs) {
}
int main(){
// Here is a 3-dimensional arr
ndvalarray<int, 3> arr;
// I want to get a slice copy of arr.
// For dimension 1, I select elements from position 1 to position 2.
// For dimension 2, I select elements from position 3 to position 6 stride 2
// For dimension 3, I select only the position 7 element
slice(arr, { 1, 2 }, { 3, 6, 2 }, {7}); // #1 error
slice(arr, { 1, 2 }, slice_info<int>{ 3, 6, 2 }, slice_info<int>{7}); // #2 yes
slice_work_around(arr, { {1, 2}, {3, 6, 2}, {7} }); // #3 yes
}
I thought #1 is an error because
braced-init-list is not an expression and therefore has no type
I tried #2 and #3, and they worked. However I am still wondering is there are possible ways to make #1 possible. This question is a bit similar with c11-variable-number-of-arguments-same-specific-type, and in my case these variable number of arguments are braced-init-list.
slice_info<T> accepts a std::initializer_list<T>, in order to describe a slice selection of a dimension, like std::slice(). ndvalarray has more than one dimension, so I have to give a pack of slice_info<T>.
I choose to implement a constructor with a std::initializer_list<T> argument, because I can use a braced-init-list, and I don't need to give T or call constructors explicitly (like #2 does). Maybe it's a bad design, but I think it's simple to use.
Related
a want to read in a vector of a struct element from a json.
JSON:
A: [
{ "list" :[
"a" : 2,
"b" : 4,
"c" : 9
]
}
my vector is : std::vector< structE > vec;
structE{ "a", "b", "c" }
if (A[i].isMember("list")) // &&
{
auto const list= A[i]["list"];
for (auto i2 = 0u; i2 < list.size(); i2++)
{
vec.push_back(list[i2]["list"]);
}
}
I have this error: matching function for call to 'std::vector ::push_back(const Json::Value&)'
I have this error: matching function for call to 'std::vector ::push_back(const Json::Value&)'
From your source code, it appears that you might be using JsonCpp to handle Json in your C++ code, when dealing with Json::Value objects, for basic types such as int and std::string, you can use Json::Value::asInt() and Json::Value::asString() respectively, however, for structs, you need to manually extract the values and construct an object of the struct with those values:
struct E {
int a, b, c;
};
// ...
E createEFromJsonValue(Json::Value const& obj) {
// Create an object of struct E with values taken from the JSON object
return {
obj.get("a", Json::nullValue).asInt(),
obj.get("b", Json::nullValue).asInt(),
obj.get("c", Json::nullValue).asInt(),
};
}
Then you can do:
// ...
vec.push_back(createEFromJsonValue(list[i2]["list"]));
// ...
I want to write a function like this:
template<class IterableType>
void CheckAndProcessIterables(IterableType& a, IterableType& b, IterableType& c) {
IteratorRangeType range{}; // empty range
if (Check(a)) {
range = boost::range::join(range, a);
}
if (Check(b)) {
range = boost::range::join(range, b);
}
if (Check(c)) {
range = boost::range::join(range, c);
}
Process(range);
}
Is it possible? Which type should I use instead of IteratorRangeType?
As far as I understand it, boost::range::join return type depends on it's arguments. Is there some wrapper class which can be assigned any type of range as long as its underlying value type is same?
You can use type erased iterator ranges, which Boost has in the form of any_range.
Beware of the performance cost of these, which can quickly become very noticable. I'd rethink the approach unless you're very sure that this not on any hot path and readability is a much more of a concern than performance.
Live On CoCompiler Explorer
#include <boost/range/join.hpp>
#include <boost/range/any_range.hpp>
// for demo only:
#include <boost/range/algorithm/for_each.hpp>
#include <boost/lambda/lambda.hpp>
#include <fmt/ranges.h>
template<class Range>
bool Check(Range const& r) {
bool odd_len = boost::size(r) % 2;
fmt::print("Check {}, odd_len? {}\n", r, odd_len);
return odd_len;
}
template<class Range>
void Process(Range const& r) {
fmt::print("Processing {}\n", r);
using namespace boost::lambda;
for_each(r, _1 *= _1);
}
template<class IterableType>
void CheckAndProcessIterables(IterableType& a, IterableType& b, IterableType& c) {
using V = typename boost::range_value<IterableType>::type;
using ErasedRange= boost::any_range<V, boost::forward_traversal_tag>;
ErasedRange range{}; // empty range
if (Check(a)) {
range = boost::range::join(range, a);
}
if (Check(b)) {
range = boost::range::join(range, b);
}
if (Check(c)) {
range = boost::range::join(range, c);
}
Process(range);
}
int main() {
std::vector a{1, 2, 3}, b{4, 5}, c{6, 7, 8};
CheckAndProcessIterables(a, b, c);
fmt::print("After process: a:{} b:{} c:{}\n", a, b, c);
}
Prints
Check {1, 2, 3}, odd_len? true
Check {4, 5}, odd_len? false
Check {6, 7, 8}, odd_len? true
Processing {1, 2, 3, 6, 7, 8}
After process: a:{1, 4, 9} b:{4, 5} c:{36, 49, 64}
I made a function that merges two sorted queues.
Queue<int> merge(Queue<int> a, Queue<int> b){
Queue<int> result;
while (!a.isEmpty() && !b.isEmpty()) {
int a1 = a.peek();
int b1 = b.peek();
if (a1 < b1) {
if (! result.isEmpty()) {
if (result.back() > a1) {
error("queue a is not sorted");
}
}
result.add(a1); // add the element to the result and make sure to remove it from the
a.dequeue(); // input queue so we don't get stuck in an infinite loop
} else {
if (! result.isEmpty()) {
if (result.back() > b1) {
error("queue b is not sorted");
}
}
result.add(b1);
b.dequeue();
}
} while (!a.isEmpty()) {
if (! result.isEmpty()) {
if (result.back() > a.peek()) {
error("queue a is not sorted");
}
}
result.add(a.front());
a.dequeue();
} while (!b.isEmpty()) {
if (! result.isEmpty()) {
if (result.back() > b.peek()) {
error("queue b is not sorted");
}
}
result.add(b.front());
b.dequeue();
}
return result;}
Now, I am trying to merge multiple queues together, recursively. Here is my thought process so far:
Divide the input collection of k sequences into two halves, left and right.
Make a recursive call to recMultiMerge on the "left" half of the sequences to generate one combined, sorted sequence. Then, do the same for the "right" half of the sequences, generating a second combined, sorted sequence.
Using the binary merge function I made above, join the two combined sequences into the final result sequence, which is then returned.
I'm having trouble on the actual recursive call, because I can't figure out how to store the result and recurse again. Here is my attempt so far:
Queue<int> recMultiMerge(Vector<Queue<int>>& all)
{
Queue<int> result = {};
Vector<Queue<int>> left = all.subList(0, all.size() / 2);
Vector<Queue<int>> right = all.subList(all.size() / 2, all.size() / 2);
if (all.isEmpty()) {
return {};
}
else if (left.size() == 1) {
return left[0];
}
else if (right.size() == 1) {
return right[0];
}
else {
Queue<int> leftCombined = recMultiMerge(left);
Queue<int> rightCombined = recMultiMerge(right);
result = merge(leftCombined, rightCombined);
}
return result;
}
The problem is, I can't get it to return more than just the first queue. Here is the problem illustrated in a test case:
on
Vector<Queue<int>> all = {{3, 6, 9, 9, 100}, {1, 5, 9, 9, 12}, {5}, {}, {-5, -5}, {3402}}
it yields
{3, 6, 9, 9, 100}
instead of
{-5, -5, 1, 3, 5, 5, 6, 9, 9, 9, 9, 12, 100, 3402}
Any advice?
An explanation of why your code gives the results you see.
The first call to recMultiMerge has 6 queues. left will be the first three ({3, 6, 9, 9, 100}, {1, 5, 9, 9, 12}, {5}), and right will be the last three ({}, {-5, -5}, {3402}).
Then you make a recursive call with left. In that call, all.size() will be 3. left will have one queue ({3, 6, 9, 9, 100}), and right will also only have one queue ({1, 5, 9, 9, 12}). (I'm assuming the 2nd parameter to Vector.subList is a count.) This will stop at the second if because left.size() == 1. The result will be that first queue.
Now we're back at the first recursive call (having lost the 2nd and 3rd queues), and we again main a recursive call with right (which has 3 queues in it). This will proceed like the last call did, returning the first queue (which in this case is empty) and losing the other two.
Then you merge those two queues ({3, 6, 9, 9, 100} and {}), resulting in your answer: {3, 6, 9, 9, 100}.
This reveals two problems: Not properly dividing a Vector with an odd number of queues in it, and terminating the recursion too early (when the left half of the split only has one queue in it, even though the right half may not be empty).
I'd start with a binary fold.
template<class X, class Op>
X binary_fold( span<X> elems, Op op );
or std::vector<X>, but I prefer span for this.
It splits elems into two pieces, then either recurses or calls op on it.
You can then test binary_fold with debugging code that simply prints the pieces on the left/right in some way, and you can see how the recursion plays out.
Once you have that, you plug back in your merge program and it should just work.
Live example.
Full code:
template<class X>
struct span {
X* b = 0;
X* e = 0;
X* begin() const { return b; }
X* end() const { return e; }
std::size_t size() const { return end()-begin(); }
X& front() const { return *begin(); }
X& back() const { return *(end()-1); }
X* data() const { return begin(); }
bool empty() const { return size()==0; }
span( X* s, X* f ):b(s),e(f) {}
span() = default;
span( X* s, std::size_t l ):span(s, s+l) {}
span( std::vector<X>& v ):span( v.data(), v.size() ) {}
template<std::size_t N>
span( X(&arr)[N] ):span(arr, N) {}
template<std::size_t N>
span( std::array<X, N>& arr ):span(arr.data(), N) {}
span except_front( std::size_t n = 1 ) const {
n = (std::min)(n, size());
return {begin()+n, end()};
}
span only_front( std::size_t n = 1 ) const {
n = (std::min)(n, size());
return {begin(), begin()+n};
}
span except_back( std::size_t n = 1 ) const {
n = (std::min)(n, size());
return {begin(), end()-n};
}
span only_back( std::size_t n = 1 ) const {
n = (std::min)(n, size());
return {end()-n, end()};
}
};
template<class X, class Op>
X binary_fold( span<X> elems, Op op ) {
if (elems.empty()) return {};
if (elems.size() == 1) return elems.front();
auto lhs = binary_fold( elems.only_front( elems.size()/2 ), op );
auto rhs = binary_fold( elems.except_front( elems.size()/2 ), op );
return op(std::move(lhs), std::move(rhs));
}
The following code groups values for any container with a generic grouping lambda:
template<class Iterator, class GroupingFunc,
class T = remove_reference_t<decltype(*declval<Iterator>())>,
class GroupingType = decltype(declval<GroupingFunc>()(declval<T&>()))>
auto groupValues(Iterator begin, Iterator end, GroupingFunc groupingFunc) {
map<GroupingType, list<T>> groups;
for_each(begin, end,
[&groups, groupingFunc](const auto& val){
groups[groupingFunc(val)].push_back(val);
} );
return groups;
}
With the following usage:
int main() {
list<string> strs = {"hello", "world", "Hello", "World"};
auto groupOfStrings =
groupValues(strs.begin(), strs.end(),
[](auto& val) {
return (char)toupper(val.at(0));
});
print(groupOfStrings); // assume a print method
list<int> numbers = {1, 5, 10, 24, 13};
auto groupOfNumbers =
groupValues(numbers.begin(), numbers.end(),
[](int val) {
int decile = int(val / 10) * 10;
return to_string(decile) + '-' + to_string(decile + 9);
});
print(groupOfNumbers); // assume a print method
}
I am a bit reluctant regarding the (over?)-use of declval and decltype in groupValues function.
Do you see a better way for writing it?
(Question is mainly for better style and clarity unless of course you see any other issue).
Code: http://coliru.stacked-crooked.com/a/f65d4939b402a750
I would probably move the last two template parameters inside the function, and use std::result_of to give a slightly more tidy function:
template <typename T>
using deref_iter_t = std::remove_reference_t<decltype(*std::declval<T>())>;
template<class Iterator, class GroupingFunc>
auto groupValues(Iterator begin, Iterator end, GroupingFunc groupingFunc) {
using T = deref_iter_t<Iterator>;
using GroupingType = std::result_of_t<GroupingFunc(T&)>;
std::map<GroupingType, std::list<T>> groups;
std::for_each(begin, end, [&groups, groupingFunc](const auto& val){
groups[groupingFunc(val)].push_back(val);
});
return groups;
}
live demo
So, I've run into this sort of thing a few times in C++ where I'd really like to write something like
case (a,b,c,d) of
(true, true, _, _ ) => expr
| (false, true, _, false) => expr
| ...
But in C++, I invariably end up with something like this:
bool c11 = color1.count(e.first)>0;
bool c21 = color2.count(e.first)>0;
bool c12 = color1.count(e.second)>0;
bool c22 = color2.count(e.second)>0;
// no vertex in this edge is colored
// requeue
if( !(c11||c21||c12||c22) )
{
edges.push(e);
}
// endpoints already same color
// failure condition
else if( (c11&&c12)||(c21&&c22) )
{
results.push_back("NOT BICOLORABLE.");
return true;
}
// nothing to do: nodes are already
// colored and different from one another
else if( (c11&&c22)||(c21&&c12) )
{
}
// first is c1, second is not set
else if( c11 && !(c12||c22) )
{
color2.insert( e.second );
}
// first is c2, second is not set
else if( c21 && !(c12||c22) )
{
color1.insert( e.second );
}
// first is not set, second is c1
else if( !(c11||c21) && c12 )
{
color2.insert( e.first );
}
// first is not set, second is c2
else if( !(c11||c21) && c22 )
{
color1.insert( e.first );
}
else
{
std::cout << "Something went wrong.\n";
}
I'm wondering if there's any way to clean all of those if's and else's up, as it seems especially error prone. It would be even better if it were possible to get the compiler complain like SML does when a case expression (or statement in C++) isn't exhaustive. I realize this question is a bit vague. Maybe, in sum, how would one represent an exhaustive truth table with an arbitrary number of variables in C++ succinctly? Thanks in advance.
I like Alan's solution but I respectfully disagree with his conclusion that it is too complex. If you have access to C++11 it gives you almost all the tools you need. You only need to write one class and two functions:
namespace always {
struct always_eq_t {
};
template <class lhs_t>
bool operator==(lhs_t const&, always_eq_t)
{
return true;
}
template <class rhs_t>
bool operator==(always_eq_t, rhs_t const&)
{
return true;
}
} // always
Then you can write your function in a way relatively similar to ML:
#include <tuple>
#include <iostream>
void f(bool a, bool b, bool c, bool d)
{
always::always_eq_t _;
auto abcd = std::make_tuple(a, b, c, d);
if (abcd == std::make_tuple(true, true, _, _)) {
std::cout << "true, true, _, _\n";
} else if (abcd == std::make_tuple(false, true, _, false)) {
std::cout << "false, true, _, false\n";
} else {
std::cout << "else\n";
}
}
int
main()
{
f(true, true, true, true);
f(false, true, true, false);
return 0;
}
In C++ you often want to consider is there a sensible type that I can create that will help me write my code more easily? Additionally, I think if you have a background in ML you will benefit a lot from examining C++ templates. They are very helpful in applying a functional programming style in C++.
C++ is traditionally oriented to the individual, and you could never do anything resembling the following regardless of syntax.
if ([a,b,c,d] == [true,true,false, false]) {}
The New C++ standard has some stuff that lets you define arrays of constants inline, and so it is possible to define a class that will take in an array as a constructor and support such comparisons. Something like
auto x = multi_val({a,b,c,d});
if (x == multi_val({true, true, false, false}))
{ ... }
else if (x == multi_val(etc.))
But now to do partial matches like with the _, that's not directly supported and you'd have to make your class even more complex to fudge with that, like using a maybe template type and going
multi_val(true, true, maybe<bool>(), maybe<bool>)
This gets into rather heady C++ territory and definitely not what I would do for something so elementary.
For C++11 assuming that you only want to match a fixed number of booleans and can live without the _ pattern matching then [1] (Expand to the number of variables you require).
I'm still working on an alternate solution using templates to match arbitrary types using lambdas or functors for the expressions.
-Edit-
As promised, [2] pattern matching of arbitrary types incl. unspecified values.
Note a couple of caveats:
This code only works with 4 variables (actually my first foray into template metaprogramming). This could very much be improved with variadic templates.
It works but it's not very tidy or well organised. More a proof of concept that would need to be cleaned up before introducing into production code.
I'm not happy with the match function. I was hoping to use initializer lists to pass the expressions to be evaluated and stop on the first match (with the current implementation every matching condition will be executed) - however i couldn't quickly think of how to pass expression matching objects of different types via the single initializer list.
I can't think of a method for either to validate that the truth table is exhaustive.
Cheers,
-nick
[1]
constexpr int match(bool v, int c)
{
return v ? (1 << c) : 0;
}
constexpr int match(bool a, bool b)
{
return match(a, 0) | match(b, 1);
}
int main()
{
int a = true;
int b = false;
switch(match(a, b))
{
case match(false, false):
break;
case match(false, true):
break;
case match(true, false):
break;
case match(true, true):
break;
}
}
[2]
template<typename V1, typename V2, typename V3, typename V4>
class pattern_match_t
{
private:
V1 value_0;
V2 value_1;
V3 value_2;
V4 value_3;
public:
typedef std::function<void(V1, V2, V3, V4)> expr_fn;
template <typename C1, typename C2, typename C3, typename C4>
pattern_match_t<V1, V2, V3, V4>& match(C1 a, C2 b, C3 c, C4 d, expr_fn fn)
{
if(value_0 == a && value_1 == b && value_2 == c && value_3 == d)
fn(value_0, value_1, value_2, value_3);
return *this;
}
pattern_match_t(V1 a, V2 b, V3 c, V4 d)
: value_0(a), value_1(b), value_2(c), value_3(d)
{
}
};
template<typename T>
class unspecified
{};
template<typename T>
constexpr bool operator==(unspecified<T>, const T&)
{
return true;
}
template<typename T>
constexpr bool operator==(const T&, unspecified<T>)
{
return true;
}
template<typename V1, typename V2, typename V3, typename V4>
pattern_match_t<V1, V2, V3, V4> pattern_match(V1 a, V2 b, V3 c, V4 d)
{
return pattern_match_t<V1, V2, V3, V4>(a, b, c, d);
}
int main()
{
bool test_a = true;
std::string test_b = "some value";
bool test_c = false;
bool test_d = true;
pattern_match(test_a, test_b, test_c, test_d)
.match(true, unspecified<std::string>(), false, true, [](bool, std::string, bool, bool)
{
return;
})
.match(true, "some value", false, true, [](bool, std::string, bool, bool)
{
return;
});
}