Reputation: 9359
I am implementing a type T
. Although this is not a requirement, users of this type may benefit from move semantic, that is T(T&&)
and T& operator=(T&&)
.
Since T
contains std::function
's as member data, I cannot implement move semantic with the noexcept
guarantees, which would make T
less useful for the user.
Also, for the above reason, my implementation cannot be as simple as: T(&&) noexcept = default
and T& operator=(T&&) noexcept = default
The alternative would be to either offer the user the non-noexcept
versions: T(&&) = default
and T& operator=(T&&) = default
; or implement my user defined noexcept
move semantic in terms of std::function::swap()
(which is guaranteed to be noexcept
). In the latter case, I would unfortunately have to take care of all the other member data other than std::function
's (ugly!).
So, there are three options:
T(&&) = default
and T& operator=(T&&) = default
T(&&) noexcept {/* lot of code */}
and T& operator=(T&&) noexcept {/* lot of code */}
I know the question is rather subjective, but What would you opt for?
Upvotes: 5
Views: 138
Reputation: 4763
Why don't you try to put all your functions in a std::function inside a std::vector then swap the vector ?
vector has noexcept move constructor.
EDIT:
To fully expand the needed concepts, i cannot reply in comments.
For your situation (different function signatures) you will require type erasure and some dynamic casts.
Here's some code that uses all the stated concepts in a coment (vector and enum and others ).
Now you can keep a vector of your lambdas , regardless of signature.
class LambdaContainer
{
public:
struct GenericContainer {
virtual ~GenericContainer(){}
};
template <typename T>
struct SpecializedContainer : GenericContainer
{
SpecializedContainer(const T& t) : lambda(t){}
virtual ~SpecializedContainer(){}
T lambda;
};
private:
std::shared_ptr<GenericContainer> myLambda;
public:
template <typename T>
LambdaContainer(const T& aLambda) : myLambda(new SpecializedContainer<T>(aLambda)){}
std::shared_ptr<GenericContainer> getContainedLambda()
{
return myLambda;
}
};
enum eFunctions
{
FCT_INT=0,
FCT_FLOAT=1
};
...
int main()
{
int aa = 10;
float b = 3.0f;
std::function<void(int)> lambda1 = [aa](int arg)
{
printf("at this time b plus argument is %d\n ",aa+arg);
};
std::function<int (float, float )> lambda2 = [b] (float arg1, float arg2)
{ printf("calling the sum of floats %f , %f\n");
return (int)(arg1+arg2+b);};
std::vector<LambdaContainer> lambdaVector;
lambdaVector.push_back(LambdaContainer(lambda1));
lambdaVector.push_back(LambdaContainer(lambda2));
std::shared_ptr<LambdaContainer::GenericContainer> container = lambdaVector[FCT_INT].getContainedLambda();
LambdaContainer::SpecializedContainer<std::function<void(int)> >* ptr =
dynamic_cast<LambdaContainer::SpecializedContainer<std::function<void(int)> >*> (container.get());
if (ptr!=NULL)
{
std::function<void(int)> extractedLambda = ptr->lambda;
extractedLambda(5);
}
std::shared_ptr<LambdaContainer::GenericContainer> container2 = lambdaVector[FCT_FLOAT].getContainedLambda();
LambdaContainer::SpecializedContainer<std::function<int(float,float)> >* ptr2 =
dynamic_cast<LambdaContainer::SpecializedContainer<std::function<int(float,float)> >*> (container2.get());
if (ptr2!=NULL)
{
std::function<int(float,float)> extractedLambda = ptr2->lambda;
printf("the sum is %d\n",extractedLambda(3.0f,2.0f));
}
}
Upvotes: 0
Reputation: 67713
Assuming you really want the noexcept
move, you can reduce the amount of boilerplate for option #3 by either:
std::function
s, orfunction
in. It just needs to implement the move ctor and assignment operator using swap, and default everything else. OK, you'll also need to either expose the function
member or forward the function call operator.Upvotes: 4