Is it possible to create a loop pattern that will allow me to change operators?
Like this
template <typename T1, typename T2, typename T3, typename T4>
auto test(T1 a, T2 b, T3 c, T4 x)
{
cout << a << endl;
cout << b << endl;
for (; a c b; a x)
{
cout << a << " |a " << this_thread::get_id() << "\n" << endl;
}
}
// main
// test(2.242, <, 20, ++);
You simply can pass any kind of function to your template. Here I use lambdas for that purpose.
As the lambdas itself are templated, you can use any kind of types in your loop.
In the loop itself we simply call the given functions. Thats easy? ;)
template <typename VAR_TYPE1, typename VAR_TYPE2, typename PREDICATE_TYPE, typename INCREMENT_FUNC_TYPE>
auto test(VAR_TYPE1 a, VAR_TYPE2 b, PREDICATE_TYPE predicate, INCREMENT_FUNC_TYPE incrementFunc )
{
std::cout << a << std::endl;
std::cout << b << std::endl;
// we simply call the given functions for the predicate/condition and the increment
for (; predicate(a,b); incrementFunc(a) )
{
std::cout << a << std::endl;
}
}
int main()
{
// use with lambdas
test( 1,9, []( auto a, auto b){ return a < b; }, []( auto& a ) { return a++; });
std::cout << std::endl;
// use with stl defined predicates
test( 1,9, std::less{} , []( auto& a ) { return a++; });
std::cout << std::endl;
test( 10.1, 5.5, std::greater{} , []( auto& a ) { return a-=0.2; });
}
Related
I am attempting to figure out how to move (or just copy if a move is not available) variadic parameters into a lambda within a templated function.
I am testing this with a move-only class (see below) because this would be the "worst-case" that needs to work with my template.
class MoveOnlyTest {
public:
MoveOnlyTest(int a, int b = 20, int c = 30) : _a(a), _b(b), _c(c) {
std::cout << "MoveOnlyTest: Constructor" << std::endl;
}
~MoveOnlyTest() {
std::cout << "MoveOnlyTest: Destructor" << std::endl;
}
MoveOnlyTest(const MoveOnlyTest& other) = delete;
MoveOnlyTest(MoveOnlyTest&& other) :
_a(std::move(other._a)),
_b(std::move(other._b)),
_c(std::move(other._c))
{
std::cout << "MoveOnlyTest: Move Constructor" << std::endl;
other._a = 0;
other._b = 0;
other._c = 0;
}
MoveOnlyTest& operator=(const MoveOnlyTest& other) = delete;
MoveOnlyTest& operator=(MoveOnlyTest&& other) {
if (this != &other) {
_a = std::move(other._a);
_b = std::move(other._b);
_c = std::move(other._c);
other._a = 0;
other._b = 0;
other._c = 0;
std::cout << "MoveOnlyTest: Move Assignment Operator" << std::endl;
}
return *this;
}
friend std::ostream& operator<<(std::ostream& os, const MoveOnlyTest& v) {
os << "{a=" << v._a << "}";
return os;
}
private:
int _a;
int _b;
int _c;
};
And here is the test code I am attempting to get working:
void test6() {
std::cout << "--------------------" << std::endl;
std::cout << " TEST 6 " << std::endl;
std::cout << "--------------------" << std::endl;
MoveOnlyTest v(1, 2, 3);
test6_A(std::move(v));
}
void test6_A(MoveOnlyTest v) {
std::cout << "test6_A()" << std::endl;
test6_B(test6_C, v);
}
template <typename ... ARGSF, typename ... ARGS>
void test6_B(void(*fn)(ARGSF...), ARGS&&... args) {
std::cout << "test6_B()" << std::endl;
//What do I need to get args to be moved/copied into the lambda
auto lambda = [fn, args = ???]() mutable {
(*fn)( std::forward<ARGS>(args)... );
};
lambda();
}
void test6_C(MoveOnlyTest v) {
std::cout << "test6_C()" << std::endl;
std::cout << "v = " << v << std::endl;
}
I am trying to have the exact same behavior as below, only using a generic template so that I can create a lambda which captures and arguments, and calls any function with those arguments.
void test5() {
std::cout << "--------------------" << std::endl;
std::cout << " TEST 5 " << std::endl;
std::cout << "--------------------" << std::endl;
MoveOnlyTest v(1, 2, 3);
test5_A(std::move(v));
}
void test5_A(MoveOnlyTest v) {
std::cout << "test5_A()" << std::endl;
auto lambda = [v = std::move(v)]() mutable {
test5_B(std::move(v));
};
lambda();
}
void test5_B(MoveOnlyTest v) {
std::cout << "test5_B()" << std::endl;
std::cout << "v = " << v << std::endl;
}
To be clear, I don't want to perfectly capture the arguments as in c++ lambdas how to capture variadic parameter pack from the upper scope I want to move them if possible and, if not, copy them (the reason being is that I plan to store this lambda for later execution thus the variables in the stack will no longer be around if they are just captured by reference).
To be clear, I don't want to perfectly capture the arguments as in c++
lambdas how to capture variadic parameter pack from the upper scope I
want to move them if possible
Just using the same form:
auto lambda = [fn, ...args = std::move(args)]() mutable {
(*fn)(std::move(args)...);
};
In C++17, you could do:
auto lambda = [fn, args = std::tuple(std::move(args)...)]() mutable {
std::apply([fn](auto&&... args) { (*fn)( std::move(args)...); },
std::move(args));
};
I have a small bit of code.
I want to know if i could cut out my ProcessArg function
I would like to loop the parameter pack from inside my call function.
Im i best to use a lambda function in initializer_list or something else, if so how do i do it.
Thanks
template <class R, class Arg>
R ProcessArg(Arg&& arg) {
std::cout << typeid(arg).name() << (std::is_reference<Arg>::value ? "&" : "") << std::endl;
//std::cout << std::boolalpha << std::is_reference<Arg>::value << std::endl; // not always true
return R();
}
template <typename R, typename... Args>
R CallFunction(Args&&... args) {
std::size_t size = sizeof...(Args);
std::initializer_list<R>{ProcessArg<R>(std::forward<Args>(args)) ...};
return R();
}
template<typename Fn> class FunctionBase;
template<typename R, typename... Args>
class FunctionBase <R(*)(Args...)> {
public:
FunctionBase() {}
R operator()(Args&&... args) { // Args&& is a universal reference
return CallFunction<R>(std::forward<Args>(args)...);
}
};
int foo(int a, int& b) {
std::cout << std::boolalpha << std::is_reference<decltype(a)>::value << std::endl; // falae
std::cout << std::boolalpha << std::is_reference<decltype(b)>::value << std::endl; // true
return a + b;
}
int main() {
int in = 10;
foo(1, in);
FunctionBase<decltype(&foo)> func;
func(1, in);
}
With c++17 fold-expressions, you can replace:
std::initializer_list<R>{ProcessArg<R>(std::forward<Args>(args)) ...};
with:
((std::cout << typeid(args).name()
<< (std::is_reference<Args>::value ? "&" : "")
<< std::endl
), ...);
Or with a lambda expression to improve readability:
auto process = [](auto&& arg) {
std::cout << typeid(arg).name()
<< (std::is_lvalue_reference<decltype(arg)>::value ? "&" : "")
<< std::endl;
};
(process(std::forward<Args>(args)), ...);
In c++20:
auto process = [] <typename Arg> (Arg&& arg) {
std::cout << typeid(arg).name()
<< (std::is_reference<Arg>::value ? "&" : "")
<< std::endl;
};
(process(std::forward<Args>(args)), ...);
I want to make a function that can wrap any lambda to log start/end calls on it.
The code below works except for:
any lambda that has captures
any lambda that returns void (although this can easily be fixed by writing a second function)
#include <iostream>
#include <functional>
template <class T, class... Inputs>
auto logLambda(T lambda) {
return [&lambda](Inputs...inputs) {
std::cout << "STARTING " << std::endl;
auto result = lambda(inputs...);
std::cout << "END " << std::endl;
return result;
};
}
int main() {
int a = 1;
int b = 2;
// works
auto simple = []() -> int {
std::cout << "Hello" << std::endl; return 1;
};
logLambda(simple)();
// works so long as explicit type is declared
auto with_args = [](int a, int b) -> int {
std::cout << "A: " << a << " B: " << b << std::endl;
return 1;
};
logLambda<int(int, int), int, int>(with_args)(a, b);
// Does not work
// error: no matching function for call to ‘logLambda<int(int), int>(main()::<lambda(int)>&)’
auto with_captures = [&a](int b) -> int {
std::cout << "A: " << a << " B: " << b << std::endl;
return 1;
};
logLambda<int(int), int>(with_captures)(b);
}
Is there any way to do this? Macros are also acceptable
Use Raii to handle both void and non-void return type,
and capture functor by value to avoid dangling reference,
and use generic lambda to avoid to have to specify argument your self
It results something like:
template <class F>
auto logLambda(F f) {
return [f](auto... args) -> decltype(f(args...)) {
struct RAII {
RAII() { std::cout << "STARTING " << std::endl; }
~RAII() { std::cout << "END " << std::endl; }
} raii;
return f(args...);
};
}
Call look like:
const char* hello = "Hello";
logLambda([=](const char* s){ std::cout << hello << " " << s << std::endl; })("world");
Demo
That code has undefined behavior.
auto logLambda(T lambda) {
return [&lambda]
You are capturing local parameter by reference.
This short C++17 program:
#include <iostream>
template <typename T> void output(T x)
{
if constexpr (std::is_integral<decltype(x)>::value) {
std::cout << static_cast<int>(x) << " is integral" << std::endl;
} else {
std::cout << x << " is not integral" << std::endl;
}
}
int main()
{
char x = 65;
output(x);
bool t = true;
output(t);
return 0;
}
Has this output:
65 is integral
1 is integral
In the template function named output, how can one detect that the argument x is boolean and not a number?
The plan is to output the value with std::cout << std::boolalpha <<, but only if the type is bool.
std::is_integral checks if a type is one of the following types: bool, char, char16_t, char32_t, wchar_t, short, int, long, long long (source). If you want to check if a type is the same as another type, std::is_same can be used. Both can be combined to get the wanted result:
template <typename T> void output(T x)
{
if constexpr (std::is_integral<decltype(x)>::value && !std::is_same<decltype(x), bool>::value) {
std::cout << static_cast<int>(x) << " is integral but not a boolean" << std::endl;
} else {
std::cout << x << " is not integral" << std::endl;
}
}
or, since we already know the type of decltype(x), which is T:
template <typename T> void output(T x)
{
if constexpr (std::is_integral<T>::value && !std::is_same<T, bool>::value) {
std::cout << static_cast<int>(x) << " is integral but not a boolean" << std::endl;
} else {
std::cout << x << " is not integral" << std::endl;
}
}
Another way can be to use a template specialization. This makes sure the other overload is being used to handle the boolean value.
template <typename T> void output(T x)
{
if constexpr (std::is_integral<T>::value) {
std::cout << static_cast<int>(x) << " is integral but not a boolean" << std::endl;
} else {
std::cout << x << " is not integral" << std::endl;
}
}
template <> void output(bool x)
{
std::cout << x << " is a boolean" << std::endl;
}
namespace fmt {
namespace adl {
template<class T>
void output( std::ostream& os, T const& t ) {
os << t;
}
void output( std::ostream& os, bool const& b ) {
auto old = os.flags();
os << std::boolalpha << b;
if (!( old & std::ios_base::boolalpha) )
os << std::noboolalpha; // restore state
}
template<class T>
void output_helper( std::ostream& os, T const& t ) {
output(os, t); // ADL
}
}
template<class T>
std::ostream& output( std::ostream& os, T const& t ) {
adl::output_helper( os, t );
return os;
}
}
now fmt::output( std::cout, true ) prints true, while fmt::output( std::cout, 7 ) prints 7.
You can extend fmt::output by creating a function in either fmt::adl or in the type T's namespace called output that takes a std::ostream& and a T const&.
void output_list_contents(std::list<tuple<string, int, double,int>> &my_list)
{
for(std::list<tuple<string, int, double,int> >::iterator it =my_list.begin(); it!= my_list.end(); ++it)
{
}
}
I'm trying to output the information from all tuples stored within an STL list. I don't know the syntax and I have spent the past hour googling for an answer, but sadly I haven't come across anything. I'm struggling with the syntax and logic to get access to the tuples stored within.
Can anyone help me out here please?
Something like:
void output_list_contents(std::list<tuple<string, int, double,int>> &my_list)
{
for(const auto& e : my_list)
{
std::cout << std::get<0>(e) << " " << std::get<1>(e) << " "
<< std::get<2>(e) << " " << std::get<3>(e) << std::endl;
}
}
First overload operator<< for tuple<string, int, double,int>:
std::ostream& opertaor<<(std::ostream& out,
tuple<string,int,double,int> const & t)
{
return out << "{" << std::get<0>(t)
<< "," << std::get<1>(t)
<< "," << std::get<2>(t)
<< "," << std::get<3>(t) << "}";
}
then use it in the loop as:
for(std::list<tuple<string, int, double,int> >::iterator it =my_list.begin();
it!= my_list.end(); ++it)
{
std::cout << *it << std::endl;
}
Oh that is ugly. Better use range-based for loop and auto:
for(auto const & item : my_list)
std::cout << item << std::endl;
Hope that helps.
A generalized implementation of operator<< for std::tuple would be this:
namespace detail
{
template<int ... N>
struct seq
{
using type = seq<N...>;
template<int I>
struct push_back : seq<N..., I> {};
};
template<int N>
struct genseq : genseq<N-1>::type::template push_back<N-1> {};
template<>
struct genseq<0> : seq<> {};
template<typename ... Types, int ...N>
void print(std::ostream & out, std::tuple<Types...> const & t, seq<N...>)
{
const auto max = sizeof...(N);
auto sink = {
(out << "{", 0),
(out << (N?",":"") << std::get<N>(t) , 0)...,
(out << "}", 0)
};
}
}
template<typename ... Types>
std::ostream& operator<<(std::ostream & out, std::tuple<Types...> const & t)
{
detail::print(out, t, typename detail::genseq<sizeof...(Types)>::type());
return out;
}
This generalized operator<< should be able to print std::tuple with any number of template arguments, as long as all template arguments support operator<< in turn.
Test code:
int main()
{
std::cout << std::make_tuple(10, 20.0, std::string("Nawaz")) << std::endl;
std::cout << std::make_tuple(10, 20.0, std::string("Nawaz"), 9089) << std::endl;
}
Output:
{10,20,Nawaz}
{10,20,Nawaz,9089}
Online Demo :-)
void output_list_contents(std::list<std::tuple<std::string, int, double, int>>& my_list)
{
for (auto tup : my_list)
{
print_tuple(tup);
}
}
And this is how print_tuple looks:
template <typename... Ts, int... Is>
void print_tuple(std::tuple<Ts...>& tup, std::index_sequence<Is...>)
{
auto l = { ((std::cout << std::get<Is>(tup)), 0)... };
}
template <typename... Ts>
void print_tuple(std::tuple<Ts...>& tup)
{
print_tuple(tup, std::index_sequence_for<Ts...>{});
}