I want to know if it is possible to store variadic template arguments into a member variable, for example a tuple? So I can use it in another method. I want it to work something like this, see below:
class TempClass
{
public:
//How can I Store the arguments with the help of a variable?
std::tuple<Template Args?> savedArgs;
template<typename ...Args>
void SaveTheseArgs(args&& ...args)
{
//Store the arguments into a variable for later use
savedArgs = std::make_tuple<Args>(args);
//Do something with the args...
}
void OtherMethod()
{
//I want to pass it back to the same method with the same arguments.
SaveTheseArgs(savedArgs);
}
}
//I tried a struct template like this, but this actually doesn't store them unless I am doing something wrong.
template<typename... Args>
struct StoredArguments
{
std::tuple<Args...> StoredArgs;
};
I am fairly new to C++ programming. I have some experience in other languages such as C#, AS3, Java.
Assuming I read your mind right, you save the args by not saving the args.
First, write this:
void DoOperation( std::tuple<int, double, std::string> const& tup ) {
auto&& some_arg_name = std::get<0>(tup);
auto&& second_arg_name = std::get<1>(tup);
// etc
// do stuff with the args
}
typedef std::function<void(TempClass*)> saved_operation;
saved_operation BuildOperation( int a, double b, std::string s ) const {
auto tup = std::make_tuple(a,b,s);
return [tup](TempClass* self){
return self->DoOperation(tup);
};
}
DoOperation takes a tuple, and does the operation using those arguments.
BuildOperation takes arguments, bundles them into a tuple, and generates a saved_operation from them.
saved_operation is basically a saved method call. I don't store this because by avoiding that, the default copy ctor does the right thing. Instead, you pass this in each time you use it.
Now using the above, we implement your stuff:
saved_operation saved_op;
template<typename ...Args>
void SaveTheseArgs(args&& ...args)
{
saved_op = BuildOperation(std::forward<Args>(args)...);
saved_op(this);
}
void OtherMethod()
{
assert(saved_op);
saved_op(this);
}
A copy of the tuple is actually stored inside the saved_operation object, but that is an implementation detail.
The trick is we care not about the data, but rather what we will do with the data later.
I used some concrete types (the int double etc), but those can just as easily be template methods as well.
If you need the efficiency, a bit more care involving moving data around instead of copying can be useful. But I kept it relatively simple. If you really need a pack of any args, you might have to google the "indexes trick" to unpack the tuple of unknown content back into parameters.
In this case, std::function is a type erasure class that erases the details of what it is constructed from, except for the fact it can be copied, destroyed, invoked with a particular signature (and also cast-back-to-source-type, which few people use).
We exploit this to "forget" the tuple and instead just remember the operation we want to do on the tuple.
This technique can be used in more general situations: you can type erase anything with a fixed signature, or really anything that can be boiled down to a fixed signature (which is a bit broader).
Words to search for for more on this topic include "runtime concepts" and "type erasure". Examining how std::function can be implemented.
Related
I have a bunch of those classes that implement a generic call operator:
template<typename T = char>
struct match {
template<initer_of_type<T> IterT>
constexpr auto operator()(IterT iter) const -> std::optional<decltype(iter)> {
// ... function body
}
// ... some members
}
// ... more similar structs
in a class template, where the operator itself is also a template.
NOTE: I'm using here a concept that I made to accept any input iterator that returns the specific value type:
template<typename IterT, typename T>
concept initer_of_type =
std::input_iterator<IterT>
&& std::is_same_v<typename IterT::value_type, T>;
That way I can use the algorithm on any iterable Ts container...
I'd like to be able to hold an array of these objects, all of which have the same template parameter T but may be different classes. It seems like I cannot use neither plain inheritence nor type erasue (at least the way I know it) because the function is a template. Is there a good way to do this? Or am I looking for the wrong solution?
#chris comment is great, if my understanding is correct, basically it add an extra layer of abstraction on your IterT thus make the match function able to be erased(and then be stored in some container)
As you said:
I'd like to be able to hold an array of these objects, all of which have the same template parameter T but may be different classes.
So it seems that we must add a new abstraction layer to work with this constraint, chris's perspective is to start with the IterT. And i'd like to provide a new perspective stolen from ThreadExecutor.
Generally almost all ThreadExecutor have such interface:
std::future<R> execute(Func&& f, Args&&... args);
Just like your situation, the args and return type are both template parameter, and ThreadExecutor also need to store these user pass task in a container. Basically, ThreadExecutor handle this by wrapping the user pass task inside a packaged_task to erase the arg type, then wrap the packaged_task inside a function wrapper or something to erase the return type.
This is a very naive code snippet, which directly use value capture and so on, but i think it can express the basic idea.
struct Container{
template<typename IterT>
void add(match<IterT> func, IterT iter){
store_.push_back(std::function([=](){
std::packaged_task([=](){
return func(iter);
})();
}));
}
std::vector<std::function<void()>> store_;
};
I recently wrote about the function of class member function callbacks. I need to save the callback object and function pointer, then call the function pointer and fill in the appropriate parameters where the callback is needed.
I started out as a form of typedef void (AAA::*Function)(int a, int b);, but when I need to support different parameter lists of member function, I obviously need a dynamic way to implement it.
class AAA
{
public:
int add(int a, int b)
{
return (a + b);
}
};
class BBB
{
public:
void setValue(std::string value)
{
this->value = value;
}
private:
std::string value;
};
class CCC
{
public:
void bind(??? p) // Binding objects and callback functions.
{
this->p = p;
}
template <class... Args>
auto callback(Args&&... args) // Autofill parameter list.
{
return this->p(std::forward<Args>(args)...);
}
private:
??? p; // How is this function pointer implemented?
};
int main()
{
AAA aaa;
BBB bbb;
CCC ccc;
ccc.bind(???(aaa, &AAA::add));
int number = ccc.callback(5, 6);
ccc.bind(???(bbb, &BBB::setValue));
ccc.callback("Hello");
system("pause");
return 0;
}
I don't know how can I implement the function pointer "???".
You basically are asking to have fully dynamicly typed and checked function calls.
To have fully dynamic function calls, you basically have to throw out the C++ function call system.
This is a bad idea, but I'll tell you how to do it.
A dynamicly callable object looks roughly like this:
using dynamic_function = std::function< std::any( std::vector<std::any> ) >
where use use
struct nothing_t {};
when we want to return void.
Then you write machinery that takes an object and a specific signature, and wraps it up.
template<class R, class...Args, class F>
struct dynamic_function_maker {
template<std::size_t...Is>
dynamic_function operator()(std::index_sequence<Is...>, F&& f)const {
return [f=std::forward<F>(f)](std::vector<std::any> args)->std::any {
if (sizeof...(Is) != args.size())
throw std::invalid_argument("Wrong number of arguments");
if constexpr( std::is_same< std::invoke_result_t<F const&, Args... >, void >{} )
{
f( std::any_cast<Args>(args[Is])... );
return nothing_t{};
}
else
{
return f( std::any_cast<Args>(args[Is])... );
}
};
}
dynamic_function operator()(F&& f)const {
return (*this)(std::make_index_sequence<sizeof...(Args)>{}, std::forward<F>(f));
}
};
template<class R, class...Args, class F>
dynamic_function make_dynamic_function(F f){
return dynamic_function_maker<R,Args...,F>{}(std::forward<F>(f));
}
next you'll want to deduce signatures of function pointers and the like:
template<class R, class...Args>
dynamic_function make_dynamic_function(R(*f)(Args...)){
return dynamic_function_maker<R,Args...,F>{}(std::forward<F>(f));
}
template<class Tclass R, class...Args>
dynamic_function make_dynamic_function(T* t, R(T::*f)(Args...)){
return dynamic_function_maker<R,Args...,F>{}(
[t,f](auto&&...args)->decltype(auto){return (t->*f)(decltype(args)(args)...);}
);
}
then after fixing typos above you should be able to solve your original problem.
Again, as someone who can actually write and understand the above code, I strongly advise you not to use it. It is fragile and dangerous.
There is almost never a good reason to store callbacks in places where you don't know what the arguments you are going to call it with.
There should be a different type and instance of CCC for each set of arguments you want to call it with. 99/100 times when people ask this question, they are asking the wrong question.
C++ is a type-safe language. This means that you cannot do exactly what you've outlined in your question. A pointer to a function that takes specific parameters is a different type from a pointer to a function that takes different parameters. This is fundamental to C++.
std::bind can be use to type-erase different types to the same type, but you get a single type at the end, that can be called only with a matching set of parameters (if any). It is not possible to invoke the "underlying" bound function, with its real parameters. That's because the whole purpose of std::bind is to make them disappear, and inaccessible. That's what std::bind is for.
You only have a limited set options to make this work while staying with the bounds and constraints of C++'s type-safety.
Make use of a void *, in some fashion. Actually, don't. Don't do that. That will just cause more problems, and headache.
Have a separate list and classes of callbacks, one list for each set of callbacks that take a specific set of parameters. You must know, at the point of invoking a callback, what parameters you intend to pass. So, just get your callback from the appropriate list.
Make use of std::variant. The type-safe std::variant is C++17 only (but boost has a similar template that's mostly equivalent, and available with older C++ revisions). All your callbacks take a single std::variant parameter, a variant of every possible set of parameters (designated as a std::tuple of them, or some class/struct instance). Each callback will have to decide what to do if it receives a std::variant containing the wrong parameter value.
Alternatively, the std::variant can be a variant of different std::function types, thus shifting the responsibility of type-checking to the caller, instead of each callback.
The bottom line is that C++ is fundamentally a type-safe language; and this is precisely one of the reasons why one would choose to use C++ instead of a different language that does not have the same kind of type-safety.
But being a type-safe language, that means that you have certain limitations when it comes to juggling different types together. Specifically: you can't. Everything in C++ is always, and must be, a single type.
---Edit for more context---
Lets say I have a class called TempClass. As the name suggests its a template class. It has a bunch of stuff that doesnt really matter to this question, but the interesting stuff is a member function called addTo and a member variable that is a unordered_map object. Lets call it inserted. Everything in inserted was put in there using addTo. What addTo should do is make some object that is then inserted into the collection at the given key. The inserted instance should be created inside of the function rather than passed to it.
addTo(KeyType key, ...) // im looking for what I should put at ...
Basically I am stuck at everything after key. I need a way I can specify the data for the newly created instance without having to worry about the objects lifetime or complicate things with calls to std::make_xxx(shared, unique etc).
Here is how I want it to be called
TempClass<std::string> stringClass();
stringClass.addTo(whereToAddIt, "This was selected because of std::string");
TempClass<Vector3f> vectorClass();
vectorClass.addTo(someOtherLocation, 12.0f,12.0f,3.0f); //adds a vec(12.0f,12.0f,3.0f)
I have seen this done this way and if this is good practice in general id love to implement it this way.
What I have tried:
Passing a pointer to the function
------> Works but is stupid. It required me to pay attention to deleting the object
Passing a temporary object and copying it before inserting
------> Works but I dislike having to copy the object just to delete it. It seems redunant and is not optimal for my specific application.
I have seen this done before, but I cant remember where (trust me I have tried to remember this, since if I could I could just look it up myself). Please explain to me in detail how to do this and how it works.
Please help me figure this out!
You can use overloads, and then enable a certain overload when your templated type is a certain type
#include <type_traits> //for enable_if and is_same
template<typename T>
class MyClass
{
public:
template<typename = std::enable_if<std::is_same_v<T, std::string>>>
void someMember(string param1, int param2);
template<typename = std::enable_if<std::is_same_v<T, Vector3f>>>
void someMember(string param1, int param2, int param3);
};
This will select the first overload is T is std:string, and the second overload if T is a Vector3f.
Edit: Looking at your edited question, a much better approach would be to just pass an instance of T to your addTo function. Like:
void addTo(std::string key, T const& value);
EDIT2: I think I finally know what you actually want. You need to use variadic templates and perfect forwarding. This might seem confusing, so I will give you code:
template<typename KeyType, typename... Args>
void addTo(KeyType key, Args&&... args)
{
//now construct the new element with:
T elem(std::forward<Args>(args)...);
}
You will need to include the utility header. For more information on variadic templates see cppreference
You can use variadic template and perfect forwarding to emplace a k/v pair:
template<class K, class V>
struct foo {
template<class... Args>
void addTo(K k, Args&&... args) {
mp.emplace(
std::piecewise_construct,
std::forward_as_tuple(k),
std::forward_as_tuple(std::forward<Args>(args)...)
);
}
std::unordered_map<K, V> mp;
};
I would like to obtain a type in a variadic template by index. The index is specified as a template argument.
I managed to find a 'hack' that works, but I believe that it is not in the spirit of variadic template programming. Besides, it uses extra memory.
Here is the code with some explanations:
template <typename... InputPortTypes>
class PipelineReceiver
{
protected:
// This tuple is used for storing types only
// Hence, I would like to get rid of it, but I am not sure how.
std::tuple<
std::function<std::unique_ptr<InputPortTypes> (int)>...
> InputPortsTuple;
// This vector is used for storing the actual objects
// This is needed to be able to access/change its elements
// during run time later on.
// The vector is used for storage of function pointers (i.e. of type std::function)
// that represent methods of another object upstream the pipeline.
std::vector<boost::any> InputPortsVector;
public:
PipelineReceiver()
{
// create an empty vector of the required size
InputPortsVector.resize(sizeof...(InputPortTypes));
}
void connectPorts(int InputPortIndex, boost::any c_OutputPort)
{
// connect ports
InputPortsVector[InputPortIndex] = c_OutputPort;
}
// this function needs to be modified to avoid using InputPortsTuple
template<int N>
void getInputPortValue(void)
{
std::cout <<
*boost::any_cast<decltype(std::get<N>(this -> InputPortsTuple))>(
InputPortsVector[N]
)(0) <<
std::endl;
}
};
I would like to remove the object InputPortsTuple and replace it with some form of a recursive procedure for inferring the types in getInputPortValue.
Ideally, I would like N to be a dynamic parameter instead of a template argument. However, I am not sure if this is possible.
You could simply abuse std::tuple_element:
typename std::tuple_element<N, std::tuple<InputPortTypes...>>::type
Note: if you can use C++14,
std::tuple_element_t<N, std::tuple<InputPortTypes...>>
is a nicer way to do the same thing. Not all common compilers know it yet, though.
I have a std::vector<T> of some type that's part of a class and that I need to iterate through in a lot of different places in my code, so I thought I'd be smart and create a function IterateAttributes, and pass it a boost::function object that I can in the loop and pass a single element and then I can pass any function to do work on the elements.
This seems a good idea until you have to implement it, then the problem comes of what does the passed in function return and does it need other arguments. It seems like I either have to find a way to do this more generically, like using templates, or I have to create overloads with function objects taking different args.
I think the first (more generic) options is probably better, however how would I go about that?
Below is a trial that doesn't work, however if I wanted to have a number of args, and all but the Attribute (a struct) arg mandatory. How should I go about it?
template <typename T> template <typename arg>
void ElementNode::IterateAttributes(boost::function<T (arg, Attribute)> func_)
{
std::vector<Attribute>::iterator it = v_attributes.begin();
for (; it != v_attributes.end(); it++)
{
func_(arg, *it);
}
}
Is that what you mean:
template <typename T, typename arg>
void ElementNode::IterateAttributes(boost::function<T (arg, Attribute)> func_, arg a)
{
std::vector<Attribute>::iterator it = v_attributes.begin();
for (; it != v_attributes.end(); it++)
{
func_(a, *it);
}
}
that allows only one parameter of any type - if you want you can introduce also version for more parameters.
About return value - what to do about it depends on what value it acctually is - the generic (and probably unnecesary) solution would be to return std::list<T>, but that would create more problems than it would solve i guess. If return type varies (not only in type but also in meaning) then I suggest modyfying templated function so it takes reference/pointer to overall result and updates it accordingly:
template <typename T> template <typename arg>
void ElementNode::IterateAttributes(boost::function<voidT (arg, Attribute, T&)> func_)
{
std::vector<Attribute>::iterator it = v_attributes.begin();
T result;
for (; it != v_attributes.end(); it++)
{
func_(arg, *it, result);
}
return result;
}
That's a quick workaround, it works but it's ugly, error prone, and pain to debug.
If you want variable parameter amount, then you would have to create several templates of above function - i just tested if it's possible:
template <typename T>
T boo(T){
}
template <typename T, typename TT>
TT boo(T,TT){
}
void test()
{
int i;
i= boo<int>(0);
i=boo<int,double>(0,0.0);
}
You must remember that functions passed to IterateAttributes must match exatly parameters given to Iterate function. That also means that you cannot use in it's prototype default values - probably you will have to define several overloaded versions like
void func_(Attribute,arg1, arg2,arg3){...}
void func_(Attribute A,arg1 a1,arg2 a2){func_(A,a1, a2,default3);}
void func_(Attribute A,arg1 a1){func_(A,a1, default2,default3);}
void func_(Attribute A){func_(A,default1, default2,default3);}
a) You want to iterate over the array and do something with each element there: in this case, you want functions that all take an array element and return void. Simple.
b) You want to partially apply functions with more arguments on each element: Write a custom functor around your function which stores the additional, pre-assigned arguments, or use boost::bind to effectively do the same.
Example:
vector<string> myStrings; // assign some values
// define a function with an additional argument
void myFunc(string message, string value)
{
cout << message << value << endl;
}
// allow partial application, i.e. "currying"
struct local_function
{
static string message;
static void myFunc_Curried(string value)
{
myFunc(message, value);
}
};
local_function::message = "the array contains: ";
// apply the curried function on all elements in the array
for_each(myStrings.begin(), myStrings.end(), local_function::myFunc_Curried);
The functor operates statically only for demonstration purposes. If message is bound to an instance of the struct, you will need something like boost::bind anyway to bind the instance pointer this in order to actually call the curried function. However, if the function I want to apply is used only locally, I prefer following the more readable static approach.
What you are trying to accomplish makes very good sense, and is also built directly into functional languages (for example F#). It is possible to achieve in C++, but requires some workarounds in the aforementioned case b. Please note if writing your own functor, as in my example, that it is common to place the arguments you want to curry away always at the beginning, and to "fill in" the arguments from the beginning to the end when partially applying.
Summarizing the comments and more thoughts:
Use bind to bind the other arguments, then use for_each on the resulting functor.
To handle return values, you need to think about what the return values mean. If you need to use the values in some way (say, perform a reduction, or use them to influence whether or not to continue performing the operation, etc), then you can use another functor to wrap the original to perform the thing you want.
You could do the same or more using BOOST_FOREACH or C++0x for each. That would even take less code to write.