---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;
};
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_;
};
Suppose that I am implementing a collection and I want to add an element to it, something like.
template <typename T>
class MyCollection
{
void add(const T& element);
};
Now, since adding element usually means copying it, for efficiency reason it makes sense to have the
following version of add as well void add(T&& element). Now the problem is that, obviously the code for both functions is exactly the same, with only difference being the argument type. My command of C++ is limited at the moment, but I would like to know whether there is a simple and idiomatic way to write the addthe function once without rewriting it twice?
In fact this is solved by defining a single overload:
void add(T element) {
where_it_is_actually_stored.insert(std::move(element));
}
Next, depending on whether you're adding a lvalue, a rvalue made from a moved lvalue, or a temporary object, the compiler will resolve an appropriate constructor so your value argument would be either copied or moved.
The most general solution, I think, would actually be this. This is what the standard library provides, so I suppose that makes it "idiomatic".
template<typename T>
struct my_collection {
template<typename... Args>
void emplace(Args&&... args) {
// construct the T object directly in its place out of std::forward<Args>(args)...
}
};
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.
I am writing a few algorithms to build random forests, each forest will be
trained on separate data with separate functions (each tree will use a set of
functions with a fixed signature however different trees will be trained using
different sets of functions which could have a different signature), however I
would like to just write the code to build the random trees once, using
templates. I currently have something like the following:
template class T corresponds to the training data type (i.e. image patch, or
pixel) template class V corresponds to the function pointer type
template<class T, class V>
class RandomTree{
void build(RandomTreeNode<T>& current_node,
vector<V>& functions,
vector<T>& data) {
... some code that basically calls a function passing in data T
}
}
and I create the object like so:
typedef double (*function_ptr)(TrainingDataPoint& data_point);
RandomTree<TrainingDataPoint, function_ptr> tree = ...
The problem is that, for efficiency reasons, for one of the trees I'm
building, I want the set of functions (function_ptr's) to take in not only the
TrainingDataPoint(template type T) but a cache of data. So that my function
pointer will look like:
typedef double (*function_ptr)(TrainingDataPoint&,
unordered_map<string, cv::Mat>& preloaded_images);
Now the problem is, I cant think of a way to keep the RandomTree class generic
but have some function sets (template type V) that take more than just the
training point (template type T).
So far I have thought of:
Making the cache global so that the functions can access it
adding a pointer to the cache to each training data point (but who is responsible for the clean up?)
Adding a third template parameter to the RandomTree, but in this case if I am building a tree that doesn't require this third parameter, what do I put there?
None of these options seem particularly appealing to me, hopefully someone can lend some experience and tell me of a better way?
Thanks
Use a functor for the functions that need state. A functor in C++ is a class (or struct) with an overloaded operator(), so that an instance of the functor can be "called like" a function. The arguments to the functor in the RandomTree should be exactly those parameters that vary and are under the control of the RandomTree, the rest should be bound outside. A sample functor with additional state that wraps a function:
template<typename Retval, typename Arg1, typename ExtraData>
struct BindExtraData
{
typedef Retval(*func_type)(Arg1, ExtraData);
BindExtraData( ExtraData const& d_, func_type func_ ):d(d_), func(func_) {};
ExtraData d;
func_type func;
Retval operator()( Arg1 a1 )
{
return func(a1, d);
}
};
but you can do better. If this is a one-off, there is no need to make it a template. bind2nd(well, binder2nd) is the standard library version of the above, and will be better written.
Can you add another paramter to RandomTree that takes in a Cache. The default would be an empty cache if not provided. For example
template<typename T, typename V, typename CacheDataType = EmptyCache>
class RandomTree{ ... }
RandomTree<TrainingDataPoint, function_ptr, ProloadedImageCache>
From the QtConcurrent documentation:
QByteArray bytearray = "hello world";
QFuture<QList<QByteArray> > future = QtConcurrent::run(bytearray, &QByteArray::split), ',');
...
QList<QByteArray> result = future.result();
The code snippet above appears to be binding a function in a similar way to std::tr1::bind (std::bind for > C++11). That is to say it's taking a non-static member function (QByteArray::split()) and (at some point later) calling it on the specific instance of the object of which it's a member (which we've supplied as bytearray).
How does Qt achieve this? Is it using std::tr1::bind or boost::bind somewhere behind the scenes?
The documentation does also refer to a case where you would use std::tr1 or boost instead, but I don't fully understand what it means by a bound function in that context. Is the situation above in fact different/more specialised/simpler than other situations where you might otherwise use tr1 or boost?
I've tried to make my way through the source but am getting lost very quickly!
I'm going to attempt a self answer, as the existing answers (many thanks to #Mike Brown and #skyhisi) lay the groundwork but don't address this specific case...
From the source:
QtConcurrent::run(...) :
template <typename T, typename Class>
QFuture<T> run(const Class &object, T (Class::*fn)())
{
return (new QT_TYPENAME SelectStoredMemberFunctionCall0<T, Class>::type(fn, object))->start();
}
SelectStoredMemberFunctionCall0:
template <typename T, typename Class>
struct SelectStoredMemberFunctionCall0
{
typedef typename SelectSpecialization<T>::template
Type<StoredMemberFunctionCall0 <T, Class>,
VoidStoredMemberFunctionCall0<T, Class> >::type type;
};
VoidStoredMemberFunctionCall0:
template <typename T, typename Class>
class VoidStoredMemberFunctionCall0 : public RunFunctionTask<T>
{
public:
VoidStoredMemberFunctionCall0(T (Class::*_fn)() , const Class &_object)
: fn(_fn), object(_object){ }
void runFunctor()
{
(object.*fn)();
}
private:
T (Class::*fn)();
Class object;
};
Given the above, I can see that Qt stores a pointer-to-member-function in the normal way, but by dressing it up in templates which would otherwise go unnoticed, the illusion of generic-ness is created.
The type of VoidStoredMemberFunctionCall0::object as well as the signature of VoidStoredMemberFunctionCall0::fn are all specified above in the arguments passed to QtConcurrent::run.
I wasn't aware that this 'implicit' templatization was even possible, to be honest. Would anybody be able to recommend further reading?
The C++ FAQ explains Pointers to member functions very well and explains the pitfalls.
At some point there would be a line similar to:
ret_val = obj_ptr->*func_ptr(param);
But it will be wrapped up in templates to allow passing any object type and parameter type, and there will be the thread dispatching mixed up in there as well.
You're passing a Function Pointer and an Instance of the Class the function was declared on. Invoking it is as simple as dereferencing the function pointer from the object. This StackOverflow Question shows the answer