I'm practicing Algorithms textbook and modern C++ coding.
I wrote a brief test that verifies sorting functions as the following:
(I know using namespace std; is discouraged in production, so please don't advice on that)
namespace frozenca {
using namespace std;
template <ranges::input_range R>
void print(R&& r, ostream& os = cout) {
for (auto elem : r) {
os << elem << ' ';
}
os << '\n';
}
mt19937 gen(random_device{}());
template <typename F, ranges::forward_range R = vector<int>> requires regular_invocable<F, R>
void verify_sorting(F&& f, int num_trials = 1'000, int max_length = 1'000) {
uniform_int_distribution<> len_dist(0, max_length);
for (int i = 0; i < num_trials; ++i) {
R v;
int n = len_dist(gen);
generate_n(back_inserter(v), n, ref(gen));
f(v);
if (!ranges::is_sorted(v)) {
throw runtime_error("Sorting verification failed");
}
}
std::cout << "Sorting verification success!\n";
}
} // namespace frozenca
and I wrote an insertion sort code like this:
namespace frozenca {
using namespace std;
struct insertion_sort_func {
template <ranges::bidirectional_range R = vector<int>, typename F = ranges::greater>
constexpr void operator()(R&& r, F comp = {}) const {
if (ranges::empty(r)) return;
for (auto i = next(begin(r)); i != end(r); ++i) {
auto key = *i;
auto j = i;
while (j != begin(r) && comp(*prev(j), key)) {
iter_swap(prev(j), j);
--j;
}
*j = key;
}
}
};
inline constexpr insertion_sort_func insertion_sort{};
} // namespace frozenca
And here is my test code, which works nicely:
int main() {
namespace fc = frozenca;
std::vector<int> v{5, 2, 4, 6, 1, 3};
fc::insertion_sort(v);
fc::print(v); // outputs "1 2 3 4 5 6"
fc::verify_sorting(std::ranges::sort); // outputs "Sorting verification success!"
fc::verify_sorting(fc::insertion_sort); // outputs "Sorting verification success!"
}
My verify_sorting function tests the sorting function for type std::vector<int> by default. Of course it can test other std::ranges::forward_range, but it becomes extremely verbose. For testing std::vector<float>, what I checked working is like this:
fc::verify_sorting<decltype(fc::insertion_sort), std::vector<float>>
(std::forward<decltype(fc::insertion_sort)>(fc::insertion_sort));
// OK
This is way too verbose. Is there any less verbose way?
Running code: https://wandbox.org/permlink/4UPLxeJxDlOkXcN1
This is way too verbose. Is there any less verbose way?
Just change the order of template parameters
template <ranges::forward_range R = vector<int>, typename F>
requires regular_invocable<F, R>
void verify_sorting(F&& f, /* */);
Then you can just invoke like this
fc::verify_sorting(std::ranges::sort);
fc::verify_sorting(fc::insertion_sort);
fc::verify_sorting<std::vector<float>>(fc::insertion_sort);
Demo
Related
Hi I'm using boost::pfr for basic reflection, it works fine, but the problem is it is only print or deal with the field values, like with boost::pfr::io it prints each member of the struct, but how can I print it as name value pairs, same issue with for_each_field, the functor only accepts values, but not names. How can I get the field names?
struct S {
int n;
std::string name;
};
S o{1, "foo"};
std::cout << boost::pfr::io(o);
// Outputs: {1, "foo"}, how can I get n = 1, name = "foo"?
If you think adapting a struct is not too intrusive (it doesn't change your existing definitions, and you don't even need to have it in a public header):
BOOST_FUSION_ADAPT_STRUCT(S, n, name)
Then you can concoct a general operator<< for sequences:
namespace BF = boost::fusion;
template <typename T,
typename Enable = std::enable_if_t<
// BF::traits::is_sequence<T>::type::value>
std::is_same_v<BF::struct_tag, typename BF::traits::tag_of<T>::type>>>
std::ostream& operator<<(std::ostream& os, T const& v)
{
bool first = true;
auto visitor = [&]<size_t I>() {
os << (std::exchange(first, false) ? "" : ", ")
<< BF::extension::struct_member_name<T, I>::call()
<< " = " << BF::at_c<I>(v);
};
// visit members
[&]<size_t... II>(std::index_sequence<II...>)
{
return ((visitor.template operator()<II>(), ...);
}
(std::make_index_sequence<BF::result_of::size<T>::type::value>{});
return os;
}
(Prior to c++20 this would require some explicit template types instead of the lambdas, perhaps making it more readable. I guess I'm lazy...)
Here's a live demo: Live On Compiler Explorer
n = 1, name = foo
Bonus: Correctly quoting string-like types
Live On Compiler Explorer
#include <boost/fusion/include/adapt_struct.hpp>
#include <boost/fusion/include/for_each.hpp>
#include <boost/fusion/include/at_c.hpp>
#include <iostream>
#include <iomanip>
namespace MyLib {
struct S {
int n;
std::string name;
};
namespace BF = boost::fusion;
static auto inline pretty(std::string_view sv) { return std::quoted(sv); }
template <typename T,
typename Enable = std::enable_if_t<
not std::is_constructible_v<std::string_view, T const&>>>
static inline T const& pretty(T const& v)
{
return v;
}
template <typename T,
typename Enable = std::enable_if_t<
// BF::traits::is_sequence<T>::type::value>
std::is_same_v<BF::struct_tag, typename BF::traits::tag_of<T>::type>>>
std::ostream& operator<<(std::ostream& os, T const& v)
{
bool first = true;
auto visitor = [&]<size_t I>() {
os << (std::exchange(first, false) ? "" : ", ")
<< BF::extension::struct_member_name<T, I>::call()
<< " = " << pretty(BF::at_c<I>(v));
};
// visit members
[&]<size_t... II>(std::index_sequence<II...>)
{
return (visitor.template operator()<II>(), ...);
}
(std::make_index_sequence<BF::result_of::size<T>::type::value>{});
return os;
}
} // namespace MyLib
BOOST_FUSION_ADAPT_STRUCT(MyLib::S, n, name)
int main()
{
MyLib::S o{1, "foo"};
std::cout << o << "\n";
}
Outputs:
n = 1, name = "foo"
The library cannot offer any such functionality because it is currently impossible to obtain the name of a member of a class as value of an object.
If you want to output field names, you need to declare string objects mapped with the members and implement a operator<< which uses these strings manually.
To do this a more sophisticated reflection library would probably offer macros to use in the definition of the members. Macros can expand their argument(s) into a declaration using the provided name as identifier while also producing code using the name as string literal (via the # macro replacement operator).
It's stupid but hey, with a stringifying macro per field it could be enough for you.
C++14, no additional library
#include <boost/pfr.hpp>
struct S
{
int n;
std::string name;
static char const* const s_memNames[2];
};
char const* const S::s_memNames[2] = {"n", "name"};
// utility
template< size_t I, typename TR >
char const* MemberName()
{
using T = std::remove_reference_t<TR>;
if (I < std::size(T::s_memNames))
return T::s_memNames[I];
return nullptr;
}
// test:
#include <iostream>
using std::cout;
template< size_t I, typename T >
void StreamAt(T&& inst)
{
char const* n = MemberName<I,T>();
auto& v = boost::pfr::get<I>(inst);
cout << "(" << n << " = " << v << ")";
}
int main()
{
S s{2, "boo"};
boost::pfr::for_each_field(s, [&](const auto&, auto I)
{
StreamAt<decltype(I)::value>(s);
cout << "\n";
});
}
output:
(n = 2)
(name = boo)
(previous version of the suggestion, this one has more fluff so less interesting)
#include <boost/pfr.hpp>
// library additions:
static char const* g_names[100];
template< size_t V >
struct Id : std::integral_constant<size_t, V > {};
template< size_t I, typename T >
using TypeAt = boost::pfr::tuple_element_t<I, T>;
template<std::size_t Pos, class Struct>
constexpr int Ni() // name index
{
return std::tuple_element_t<Pos, typename std::remove_reference_t<Struct>::NamesAt >::value;
}
struct StaticCaller
{
template< typename Functor >
StaticCaller(Functor f) { f();}
};
///
/// YOUR CODE HERE
struct S
{
using NamesAt = std::tuple<Id<__COUNTER__>, Id<__COUNTER__>>; // add this
int n;
std::string name;
static void Init() // add this
{
g_names[Ni<0,S>()] = "n";
g_names[Ni<1,S>()] = "name";
}
};
StaticCaller g_sc__LINE__(S::Init); // add this
// utilities
template< size_t I, typename T >
auto GetValueName(T&& inst)
{
return std::make_pair(boost::pfr::get<I>(inst), g_names[Ni<I,T>()]);
}
// test:
#include <iostream>
using std::cout;
template< size_t I, typename T >
void StreamAt(T&& inst)
{
auto const& [v,n] = GetValueName<I>(inst);
cout << "(" << v << ", " << n << ")";
}
int main()
{
S s{2, "boo"};
boost::pfr::for_each_field(s, [&](const auto&, auto I)
{
StreamAt<decltype(I)::value>(s);
cout << "\n";
});
}
output
(2, n)
(boo, name)
I want to get a matrix from two parameter packs like the following:
template < typename T1, typename T2 > struct Multi{};
template < int ... n > struct N{};
void Print( int n ){ std::cout << n << std::endl; }
template < int ... n1, int ... n2 >
struct Multi< N<n1...>, N<n2...>>
{
Multi()
{
using expander = int[];
// No idea which syntax should be used here:
expander{ 0,((void)Print(n1...*n2),0)... };
}
};
int main()
{
Multi< N<1,2,3,4>, N< 10,20> >{};
}
The result should be
10 20 30 40 20 40 60 80
How can I do this?
No need to use the dummy arrays when you have fold expressions.
The naive (Print(n1 * n2), ...); wouldn't work (it expects the packs to have the same size, and would print N numbers instead of N2).
You need two nested fold expressions. In the inner one, you can prevent one of the packs from being expanded by passing it as a lambda parameter.
([](int n){(Print(n1 * n), ...);}(n2), ...);
This is not single expression, but you can expand it and use for loop
template < int ... n1, int ... n2 >
struct Multi< N<n1...>, N<n2...>>
{
Multi()
{
for(auto j : {n2...})
for(auto i : {n1...})
std::cout << i*j << '\n';
}
};
WandBox
I kind of assume that the output in your code is to check the compile time evaluation, since the output to std::cout only works at runtime.
Another option is not to use structs but to use constexpr functions,
they look more like regular c++ code. And you van validate the correctness at compile time using static_asserts. I did add some output at the end of my example
live demo here : https://onlinegdb.com/iNrqezstg
#include <array>
#include <iostream>
template<int... n>
constexpr auto array()
{
return std::array<int,sizeof...(n)>{n...};
};
template<std::size_t N, std::size_t M>
constexpr auto multiply(const std::array<int, N>& arr1, const std::array<int, M>& arr2)
{
std::array<int, N* M> result{};
std::size_t index{ 0 };
for (std::size_t n = 0; n < N; n++)
{
for (std::size_t m = 0; m < M; m++)
{
result[index] = arr1[n] * arr2[m];
++index;
}
}
return result;
}
template<typename container_t>
void show(const char* msg, const container_t& values)
{
std::cout << msg << " : ";
bool comma{ false };
for (const auto& value : values)
{
if (comma) std::cout << ", ";
std::cout << value;
comma = true;
}
std::cout << "\n";
}
int main()
{
constexpr auto arr1 = array<1, 2, 3, 4>();
constexpr auto arr2 = array<10, 20>();
constexpr auto result = multiply(arr1, arr2);
static_assert(arr1[0] == 1, "");
static_assert(arr2[1] == 20, "");
static_assert(result[0] == 10, "");
static_assert(result[1] == 20, "");
static_assert(result[6] == 40, "");
show("arr1", arr1);
show("arr2", arr2);
show("result", result);
return 0;
}
I was wondering if it possible to create custom functions like for, for_each, while etc.
There's nothing that I want to do that the existing loops won't do it. I am just curious to learn how they work and if I ever need to create my own.
For example if one wants to create another version of the for function that would take only parameter.
In this example, I want to to create a for that only takes one parameter, an integer.
Instead of writing
for (int i = 0; i < 50; ++i)
I would create a for version like this
for_(50)
and they would act the same. How would I do something like that?
I have posted this question in another forum.
In addition to the proposals in other answers, you could create a function like the one below, but it is, at the very end, very similar to using the standard std::for_each.
#include <iostream>
#include <functional>
template<typename C, typename F>
void for_(C begin_, C end_, F&& f) { // [begin_, end_)
for (C i = begin_; i < end_; ++i) {
f(i);
}
}
template<typename C, typename F>
void for_(C count, F&& f) { // special case for [0, count)
for_(0, count, f);
}
void mul2(int x) {
std::cout << x*2 << " ";
}
int main() {
for_(10, [](int i) { std::cout << i << "\n"; });
for_(2, 10, mul2);
}
An ugly and unsafe solution is to use macro:
#define REPEAT(i,N) for(int (i) = 0; (i) < (N); ++(i))
int main()
{
REPEAT(i,10) std::cout << i << std::endl;
return 0;
}
You can't extend the C++ syntax for new loops.
You could use a macro, but this is pretty ugly, and generally best avoided. Another way to get something similar is by passing a functor as a parameter, greatly helped by the introduction of lambda expressions to C++. You can find some examples of such in the <algorithm> header.
For example:
#include <algorithm>
#include <vector>
int main()
{
std::vector<int> numbers = { 1, 4, 5, 7, 10 };
int even_count = 0;
for (auto x : numbers)
{
if (x % 2 == 0)
{
++even_count;
}
}
auto even_count2 = std::count_if(numbers.begin(), numbers.end(), [](int x) { return x % 2 == 0; });
}
You could use a lambda function and pass in a function object as a parameter to be performed for every iteration of the loop.
#include <iostream>
#include <functional>
int main()
{
auto for_ = [](int start, int size, std::function<void (int i)> fn)
{
int end = start + size;
for (int i = start; i < end; ++i)
{
fn(i);
}
};
for_(0, 10, [](int i) { std::cout << i << std::endl; });
for_(0, 10, [](int i) { std::cout << i*2 << std::endl; });
}
It seems like you are reinventing the wheel here a bit. You could just use std::for_each.
However, you could have custom lambda functions that do different things and just implement the operation within the lambda itself without taking in a function object for the operation.
How does one do two type variadic expansion? Here is what I am trying to achieve:
#include <vector>
#include <iostream>
class test
{
public:
std::vector< std::pair< float, int > > vec;
template<typename... T1, typename... T2>
test( T1... one, T2... two )
{
(
[&](float first, int second)
{
vec.emplace_back( std::pair< float, int >( first, second ) );
std::cout << first << ", " << second << std::endl;
}( one, two ),
...
);
}
};
int main()
{
test t
{
1.f,
1,
2.f,
2,
3.f,
3
};
return 0;
}
test must be initialized exactly like in main. I'd like usage in the constructor of test to remain similar.
Here is a working concept with va_list. Unfortunately, I need to pass a count for the parameters or I need to pass a magic-number terminator (I opted for the magic-number terminator).
#include <cstdarg>
#include <iostream>
#include <vector>
constexpr int END_OBJECT = 890123; // magic number
class test {
public:
std::vector<std::pair<int, double>> vec;
enum { is_name, is_data, is_max };
test(char ch, ...) {
std::pair<int, double> buf;
va_list b;
va_start(b, ch);
for (int i = 0;; i++) {
auto is = i % is_max;
if (is == is_name) {
if ( (buf.first = va_arg(b, int)) == END_OBJECT )
break;
} else if (is == is_data) {
buf.second = va_arg(b, double);
vec.emplace_back(buf);
}
}
va_end(b);
std::cout << ch << std::endl;
for (auto &x : vec)
std::cout << '\t' << x.first << ", " << x.second << std::endl;
}
};
int main() {
test t
{
'x',
1,
2.0,
3,
4.0,
5,
6.0,
END_OBJECT
};
return 0;
}
I'd like a more modern version of this using pack-expansion.
It's funny how this is basically FizzBuzz with template arguments and it's actually a nice challenge.
The easiest way in C++14 I could come up with is to use std::index_sequence.
https://godbolt.org/z/dm3F9u
#include <vector>
#include <utility>
#include <tuple>
template <typename... TArgs, size_t... Is>
std::vector<std::pair<float, int>> pair_off(std::tuple<TArgs...> args, std::index_sequence<Is...>) {
return std::vector<std::pair<float, int>> { std::make_pair(std::get<(Is << 1)>(args), std::get<((Is << 1) + 1)>(args))... };
}
template <typename... TArgs>
std::vector<std::pair<float, int>> pair_off(TArgs&&... args) {
return pair_off(std::forward_as_tuple(std::forward<TArgs>(args)...), std::make_index_sequence<(sizeof...(TArgs) >> 1)>{});
}
std::vector<std::pair<float, int>> test() {
return pair_off(1.1f, 1, 2.2f, 2, 3.3f, 3);
}
Basically, first you pack the arguments into a tuple. Then you make an index sequence half the size of the argument list. Then you expand that index sequence, passing it into std::get.
What that does is the template equivalent of:
for (int i=0; i<list.size()/2; i++) {
output.push_back( std::make_pair(list[i*2], list[i*2+1]) );
}
Here is my code:
#include <functional>
#include <iostream>
#include<vector>
using namespace std;
// vector iterator
template <class T> class vit
{
private:
//vector<T>::iterator it;
vector<T> m_v;
function<bool (T, T)> m_fptr;
int len, pos;
public:
vit(vector<T> &v) { this->m_v = v; len = v.size(); pos = 0;};
// it= v.begin(); };
bool next(T &i) {
//if(it == m_v.end()) return false;
if(pos==len) return false;
//i = *it;
i = m_v[pos];
//if(idle) { idle = false ; return true; }
//it++;
pos++;
return true;};
//bool idle = true;
void set_same(function<bool (T,T)> fptr) { m_fptr = fptr ;};
//void set_same(function<bool(int, int)> fun) { return ; }
bool grp_begin() {
return pos == 0 || ! m_fptr(m_v[pos], m_v[pos-1]); };
bool grp_end() {
return pos == len || ! m_fptr(m_v[pos], m_v[pos+1]); };
};
bool is_same(int a, int b) { return a == b; }
main()
{
vector<int> v ={ 1, 1, 2, 2, 2, 3, 1, 1, 1 };
int total;
for(auto it = v.begin(); it != v.end(); it++) {
if(it == v.begin() || *it != *(it-1)) {
total = 0;
}
total += *it;
if(it+1 == v.end() || *it != *(it+1)) {
cout << total << endl;
}
}
cout << "let's gry a group" <<endl;
vit<int> g(v);
int i;
while(g.next(i)) { cout << i << endl; }
cout << "now let's get really fancy" << endl;
vit<int> a_vit(v);
//auto is_same = [](int a, int b) { return a == b; };
a_vit.set_same(is_same);
//int total;
while(a_vit.next(i)) {
if(a_vit.grp_begin()) total = 0;
total += i;
if(a_vit.grp_end()) cout << total << endl ;
}
}
When I compile it with g++ -std=c++11 iter.cc -o iter, I get the result:
iter.cc: In function 'int main()':
iter.cc:63:17: error: reference to 'is_same' is ambiguous
a_vit.set_same(is_same);
^
iter.cc:37:6: note: candidates are: bool is_same(int, int)
bool is_same(int a, int b) { return a == b; }
^
In file included from /usr/include/c++/5.3.0/bits/move.h:57:0,
from /usr/include/c++/5.3.0/bits/stl_pair.h:59,
from /usr/include/c++/5.3.0/utility:70,
from /usr/include/c++/5.3.0/tuple:38,
from /usr/include/c++/5.3.0/functional:55,
from iter.cc:1:
/usr/include/c++/5.3.0/type_traits:958:12: note: template<class, class> struct std::is_same
struct is_same;
^
By way of explanation, I have created a class called 'vit'. It does two things: iterate over a vector, and determine if a new group has been reached.
The class function 'set_same' is supposed to store a function provided by the calling class to determine if two adjacent elements of a vector are in the same group. However, I can't seem to store the function in the class for future use by grp_begin() and grp_end() on account of the ostensible ambiguity of is_same.
What gives?
There is an is_same function defined by you and there is a struct is_same defined by the C++ Standard Library. Since you are using namespace std, your compiler doesn't know which is_same you meant to use.
It's what the error says: it's not clear whether you mean your is_same (in the global namespace) or the class template is_same (in namespace std).
You may disambiguate as follows:
::is_same
… with the leading :: meaning "in the global namespace".
Though you should consider putting your code in a namespace of its own.
Thanks guys. This is my first time touching C++ after more than a decade. I have cleaned up the code, and used a lambda to bring the "is_same" function closer to where it is called.
Did you spot the bug in my code? 'pos' was off-by-one when calling grp_begin() and grp_end(). Here is the revised code:
#include <functional>
#include <iostream>
#include <vector>
// vector iterator
template <class T> class vit
{
private:
std::vector<T> m_v;
std::function<bool (T, T)> m_fptr;
int len, pos;
public:
vit(std::vector<T> &v) { m_v = v; len = v.size(); pos = -1;};
bool next(T &val) {
pos++;
if(pos==len) return false;
val = m_v[pos];
return true;};
void set_same(std::function<bool (T,T)> fptr) { m_fptr = fptr ;};
bool grp_begin() {
return pos == 0 || ! m_fptr(m_v[pos], m_v[pos-1]); };
bool grp_end() {
return pos+1 == len || ! m_fptr(m_v[pos], m_v[pos+1]); };
};
main()
{
std::vector<int> v ={ 1, 1, 2, 2, 2, 3, 1, 1, 1 };
vit<int> a_vit(v);
std::function<bool (int, int)> is_same = [](int a, int b) { return a == b; };
a_vit.set_same(is_same);
int i, total;
while(a_vit.next(i)) {
if(a_vit.grp_begin()) total = 0;
total += i;
if(a_vit.grp_end()) std::cout << total << std::endl ;
}
}
My class definition isn't bullet-proof and could be better: if the user forgets to 'set-same', for example, they'll be referring a random memory address as a function.
Nevertheless, I'm pretty chuffed with my solution so far. The class caller is relieved of all the bookkeeping relating iterating over the vector, and working out if a group boundary has been crossed.
The calling code looks very compact and intuitive to me.I can see C++ being my go to language.