I was under the impression that I don't need a template in order to use variadics in C++. So in the following class, I have a method that accepts a variadic as its second variable. Now my question is: how do I iterate over the variadic?
class CoolClass{
/** Other stuff go here */
// my question is about this
void variadic(X d, X others...){
cout<<"Main is "<<d.value()<<endl;
cout<<"Others are: "<<endl;
for(const auto& o: { others... }){ // doesn't have to be const
cout<<o.value()<<endl;
}
}
};
I tried running the code above and it doesn't work. I changed from { others...} to simply others`, but that doesn't work either.
Related
I currently have 2 nearly-identical (functionality-wise) functions:
class MyClass
{
public:
void CallFunc(auto fncPtr)
{
fncPtr();
}
void CallMemFunc(auto (MyClass::*fncPtr)())
{
(this->*fncPtr)();
}
};
Is there any way to combine both generic functions into a single generic function?
Either by somehow generalizing the function's parameter further, or by adding both as separate parameters (with some default values) to the function?
To clarify, the above functions serve as a simple example to what I'm trying to achieve - My code has 2 functions with near-identical functionality that differ only by the fact that one of them handles a pointer-to-member-function while the other handles a pointer-to-general-function, like in the above case (though my issue isn't with the above functions per-se).
Not sure it is what you want and if it is better than simple overload, but you can do:
void Call(auto func)
{
if constexpr (std::is_invocable_v<decltype(func)>) {
std::invoke(func);
} else if constexpr (std::is_invocable_v<decltype(func), MyClass*>) {
std::invoke(func, this);
}
}
Demo
I have found that sometimes functions have very many parameters. A great many of these parameters will be optional and sometimes a group of these options often come from a single other object (so you end up doing foo(Object.GetN(), Object.GetM(), Object.GetK())). A common way to deal with it is to create different overloads for different situations that it might be called:
foo(int n, int m, int k /*, and on and on*/);
foo(bool b, int m/*, ...*/);
foo(int m, int k/*, ...*/);
foo(Object_t object/*, ...*/);
//...
The problem here is that which parameter is which isn't particularly intuitive and you can get quite the surprise when you call a different overload than what you intended.
Recently I had an idea to make it easier to get the function call right and make life easier for myself when dealing with these functions that have many different ways of being called. This solution doesn't cover every possible necessity out there, but it works quite well for me.
Instead of creating different overloads for everything, I would create 1 function that simply takes a variadic number of parameters and then extract possible parameters for use inside the function. As for the parameters, I would wrap them in helper classes that would be created for these functions. This would allow for the user declaring what each integer or boolean or string or what-have-you means instead of relying on positional information within the function's signature.
Instead of foo(n, m) (which going by the names of the variables above suggests a likely bug) you would call foo(OptN(n), OptM(m)) making it completely clear what each parameter is going to be used for and much harder to have a parameter be misinterpreted.
I will include a MCVE at the end if anyone's interested in 1 possible implementation of this.
I have never seen or heard of this technique before, but I also have a hard time believing that I'm the first one to think of it. So, finally, my question is simply does this technique have a name already?
If it doesn't have a name already, I have been calling these functions 'declarative functions' since you declare what each parameter represents explicitly instead of 'positional functions' relying on where the parameter appears to give it its meaning.
MCVE:
#include <iostream>
#include <utility>
struct Option1
{
Option1(bool b):b(b){}
bool b;
bool operator()() const {return b;}
};
struct Option2
{
Option2(int n):n(n){}
int n;
int operator()() const {return n;}
};
struct Group : Option1, Option2
{
Group(bool b, int n):Option1(b), Option2(n){}
};
/*
* Get the option from what the user gave us.
*/
template <class OptionType, class OptionsGetter, class RType>
auto GetOptionImpl(const OptionsGetter & options_getter,
const RType&, std::true_type) ->
decltype(((const OptionType&)options_getter)())
{
return ((const OptionType&)options_getter)();
}
/*
* Get the default value specified since the user didn't pass
* in that option
*/
template <class OptionType, class OptionsGetter, class RType>
RType GetOptionImpl(const OptionsGetter&, const RType & d, std::false_type)
{
return d;
}
/**
* Returns the value of the option OptionType if the user
* passed that in (inside OptionsGetter) and returns the
* default value if they didn't pass it in.
*/
template <class OptionType, class OptionsGetter, class RType>
auto GetOption(const OptionsGetter & oOptionsGetter,
const RType & oDefault) ->
decltype(std::declval<OptionType>()())
{
return GetOptionImpl<OptionType>(oOptionsGetter, oDefault,
std::is_base_of<OptionType, OptionsGetter>());
}
template <class ... Params>
void foo(Params ... params)
{
struct ParamsGetter : Params...
{
ParamsGetter(Params ... p): Params(p)...{}
} params_getter(params...);
if(GetOption<Option1>(params_getter, false))
std::cout << "Option 1 was true ";
else
std::cout << "Option 1 was false ";
std::cout << "Option 2: " << GetOption<Option2>(params_getter, 3) << '\n';
}
int main()
{
foo(Option1{true}, Option2{22});
foo();
foo(Option2{1});
foo(Group(true, 2));
}
Output:
Option 1 was true Option 2: 22
Option 1 was false Option 2: 3
Option 1 was false Option 2: 1
Option 1 was true Option 2: 2
As mentioned in a comment, this concept is called named parameter. See the explanation on wikipedia, as well as for instance this proposal to introduce it in C++.
I think this is commonly called an opaque typedef or a strong typedef. The idea is to solve the exact problem you're describing - you have types that have integral values but you want to make it possible to explicitly set them.
For more motivation on this concept, you can see this proposal for inclusion in the language and Boost's implementation of it.
I find myself encapsulating multiple lambdas in a "proxy" object with a nicer interface in various parts of my code:
auto create_proxy()
{
auto f_get_foo = [something]
{
return something_else();
};
auto f_set_bar = [something](auto x)
{
something_else(x);
};
auto f_render = [&window]
{
window.render();
};
return make_nice_proxy( // .
std::move(f_get_foo), // .
std::move(f_set_bar), // .
std::move(f_render));
}
I can use the proxy like this:
nice_proxy.get_foo(); // calls the stored `f_get_foo` lambda
nice_proxy.set_foo(15); // calls the stored `f_set_foo` lambda
nice_proxy.render(); // calls the stored `f_render` lambda
The problem is that writing and maintaining code for these proxies is very cumbersome and syntactically heavy:
template < // .
typename TFGetFoo, // .
typename TFSetBar, // .
typename TFRender // .
>
class nice_proxy_impl
{
// Hide the lambdas:
private:
TFGetFoo _f_get_foo;
TFSetBar _f_set_bar;
TFRender _f_render;
int _render_count = 0;
public:
template < // .
typename TFwdFGetFoo, // .
typename TFwdFSetBar, // .
typename TFwdFRender // .
>
nice_proxy_impl( // .
TFwdFGetFoo&& f_get_foo, // .
TFwdFSetBar&& f_set_bar, // .
TFwdFRender&& f_render) // .
: _f_get_foo(FWD(f_get_foo)),
_f_set_bar(FWD(f_set_bar)),
_f_render(FWD(f_render))
{
}
// Expose the lambdas:
void set_bar(int x)
{
some_side_effect();
_f_set_bar(x);
}
auto get_foo()
{
return _f_get_foo();
}
void render()
{
std::cout << "rendering...\n";
_f_render();
++_render_count;
}
};
template <typename... TFs>
auto make_nice_proxy(TFs&&... fs)
{
return nice_proxy_impl<std::decay_t<TFs>...>(FWD(fs)...);
}
The purpose of the proxy class is to:
Hide the lambdas from the user.
Give the users a nice (and possibly richer) interface through which they can call the "hidden" lambdas.
I have multiple proxy classes in my codebase, which all privately store some perfectly-forwarded callable objects (and expose them through public functions), and that are created using make_xxx_proxy functions.
While make_xxx_proxy is usually easy to implement and does not require much maintenance, every proxy class (like nice_proxy_impl) require one template parameter per function, one field per function and one perfect-forwarding constructor parameter.
With multiple proxy classes, even adding or removing a single "encapsulated function" becomes annoying fairly quickly. get_foo is repeated 5 times in nice_proxy_impl (in different forms).
Is there a better and less syntactically-heavy solution for this "pattern"?
I'm looking for a way of avoiding the constant lambda/function repetition, type decaying and perfect-forwarding, which is just boilerplate.
make_xxx_proxy functions also become hell to maintain if the passed arguments are not only functions, but also additional field. Parameter expansion cannot be used in that case, and every single function has to be decayed and forwarded.
Here's a real example of a make_xxx_proxy-like function. Proxies may contain additional data/methods, that use the "encapsulated lambdas" and additional fields in various ways. Here's the corresponding proxy class.
Not sure I understand what you're actually asking, but you could reduce make_nice_proxy to just return a local class (thanks to C++14) with public members (so you can aggregate-initialize). This avoids having to rewrite most stuff:
template <class Getter, class Setter, class Render>
auto make_nice_proxy(Getter&& g, Setter&& s, Render&& r)
{
struct Proxy {
std::decay_t<Getter> _f_get_foo;
std::decay_t<Setter> _f_set_bar;
std::decay_t<Render> _f_render;
int _render_count = 0;
void set_bar(int x) {
some_side_effect();
_f_set_bar(x);
}
auto get_foo() {
return _f_get_foo();
}
void render() {
std::cout << "rendering...\n";
_f_render();
++_render_count;
}
};
return Proxy{std::forward<Getter>(g), std::forward<Setter>(s), std::forward<Render>(r)};
}
I'm working with the following class design and would like to get rid of the same for-loop in each of the forwarding method calls by using some sort of delegate/member pointer. Is this somehow possible?
class Type
{
void func_v();
// more methods ...
bool func_b();
// ...
unsigned func_u();
// ...
}
class MultiType : public Type
{
void func_v() override
{
for(Type* type : _typeVec)
type->func_v();
}
bool func_b() override
{
bool result = true;
for(Type* type : _typeVec)
result = result && type->func_b();
return result;
}
unsigned func_u() override
{
int count = 0;
for(Type* type : _typeVec)
count += type->func_u();
return count;
}
protected:
std::vector<Type*> _typeVec;
}
What I'm looking for is something similar to this:
class MultiType : public Type
{
void applyMember(MemberType member)
{
for(Type* type : _typeVec)
// how to deal with varying parameters and parameter types here?
type->member(...)
// how to deal with varying return values and processing strategies to combine those?
}
void func_v() override
{
applyMember(&Type::func_v);
}
bool func_b() override
{
applyMember(&Type::func_b);
}
unsigned func_u() override
{
applyMember(&Type::func_u);
}
protected:
std::vector<Type*> _typeVec;
}
Since all your example functions perform different actions I would recommend you to look into accumulate and for_each algorithms.
You could replace your raw loops with something like this:
bool func_b() override
{
return std::accumulate(_typeVec.begin(), _typeVec.end(), true, [](const bool &result, const Type *t) {
return result && type->func_b();
});
}
void func_v() override
{
std::for_each(_typeVec.begin(), _typeVec.end(), [](Type *type){type->func_v()});
}
The "What I'm looking for..." part in your question doesn't work. For example, func_b doesn't return any value. Even if you could do something like that using a combination of template functions and lambdas, you'd have the same independent parts in all functions (local variable declaration, reduction mechanism, return statement). The only thing you could abstract away is the for loop, but that's just a single line you'll be replacing with a different line.
There's no point doing that.
From what I understand of your question, you would want to call the same method, and possibly use the same parameters, on each object.
For example, in your production code, func_v would take parameters. This may be different from func_b that may not take parameters.
Let us assume that func_v takes in a int.
In this case, would this be true?
MultiType::func_v(int value) {
for (Type* type : _typeVec)
type->func_v(value); //note: same value being passed to all
}
You may want to use functors here. However, I don't think that will work well with multiple return values.
Functors can be used to aggregate values. Is that what you want to do?
Forgetting abstracting the loop out, how will you return multiple values from func_v above?
So if returning multiple values is not a problem, functors can be what you want to do.
It may be too much work for too little though. You will have to find out if it is worth it in your production code.
I have a filter which is supposed to work on arbitrary tensors. For my case it is sufficient when the filter works on rank 1,2 and 3 tensors which are lists, matrices and 3d-matrices or volumes respectively. Additionally, the filter can be applied in each possible direction. For a list this is only one, for matrices exist 2 possible directions (namely X-direction and y-direction) and for volumes exist 3 possible direction.
Before I go into detail let me ask my question first: Is my layout of the filter ok or did I forgot something important which maybe gives me a hard time later? I'm not new to C++ templates, but it's not that I feel like a fish in water. Is it possible to compress this layout further (maybe there's a way around the dummy XDirection classes or a shorter Type2Type)?
The basic procedure of the filter is for every tensor-rank and for every direction the same. There is just a few lines of code, the function callKernel, which are different. To make the overloaded operator() call the right callKernel function is the only interesting part in the code below. Since partial specialization for templates does not work for class-methods, you can convert the template arguments into a real class-type and give this as dummy argument to callKernel.
The following code is they layout up to rank 2. It is compileable with g++ and can be tried.
template <class DataType, int Rank>
class Tensor { };
class XDirection;
class YDirection;
template <class TensorType, class Direction>
struct Type2Type {
typedef TensorType TT;
typedef Direction D;
};
template <class TensorType, class Direction>
struct Filter {
Filter(const TensorType &t){}
TensorType operator()(){
/* much code here */
callKernel(Type2Type<TensorType,Direction>());
/* more code */
TensorType result;
return result;
}
void callKernel(Type2Type<Tensor<double,1>, XDirection>) {}
void callKernel(Type2Type<Tensor<double,2>, XDirection>) {}
void callKernel(Type2Type<Tensor<double,2>, YDirection>) {}
};
int main(void) {
Tensor<double, 2> rank_two_tensor;
Filter<Tensor<double,2>,XDirection> f(rank_two_tensor);
f();
}
Let me add some important things: It is necessary that the filter-logic is in the operator() because what you see here is going used with the Intel Threading Building Blocks which require this structure. It is very important, that the callKernel is inlined. From everything I know, this should be the case.
Thanks in advance for any helpful and critical comment.
First, not bad for a first try on templates.
If you have a recent version of GCC you can simplify like this, there's a better way to execute code conditionally on a type using std::is_same<>. It will return true if the types are identical. It also makes your intent more explict.
#include <type_traits>
template <class TensorType, class Direction>
struct Filter {
Filter(const TensorType &t) { }
TensorType operator()(){
/* much code here */
callKernel();
/* more code */
TensorType result;
return result;
}
void callKernel() {
// Check which type is called at compile time (the if will be simplified by the compiler)
if (std::is_same<TensorType, Tensor<double, 2> >::value) {
if (std::is_same<Direction, XDirection>::value) {
// do stuff
} else {
...
}
} else if (...) {
...
}
}
};
Edit: If you wish you can even move it to op() to make sure the code is inlined.