Found this code which looks to be interesting:
auto a = [](){};
class B : decltype(a)
{
};
I want to know what it does. Can this be useful in any way?
Well, that code will compile, but the problem is that you will be unable to default construct any object of that class1, because the constructor of the lambda isn't accessible (other than copy/move constructors). The only constructors guaranteed by a lambda type is a defaulted copy/move constructor. And there's no default constructor
[expr.prim.lambda/21]
The closure type associated with a lambda-expression has no default
constructor and a deleted copy assignment operator. It has a defaulted
copy constructor and a defaulted move constructor ([class.copy]). [
Note: These special member functions are implicitly defined as usual,
and might therefore be defined as deleted. — end note ]
or from cppreference:
//ClosureType() = delete; //(until C++14)
ClosureType(const ClosureType& ) = default; //(since C++14)
ClosureType(ClosureType&& ) = default; //(since C++14)
The history of the lambda constructor being inaccessible dates back to its early days proposal, found here
In section 3, second paragraph, and I quote:
In this translation, __some_unique_name is a new name, not used
elsewhere in the program in a way that would cause conflicts with its
use as a closure type. This name, and the constructor for the class,
do not need to be exposed to the user—the only features that the user
can rely on in the closure type are a copy constructor (and a move
constructor if that proposal is approved) and the function call
operator. Closure types do not need default constructors, assignment
operators, or any other means of access beyond function calls. It may
be worthwhile for implementability to forbid creating derived classes
from closure types. ...
As you can see, the proposal even suggested that creating derived classes from closure types should be forbidden.
1 of course you can copy-initialize the base class with a in order to initialize an object of type B. See this
Now, to your question:
Can this be useful in any way?
Not in your exact form. Your's will only be instantiable with the instance a.
However, if you inherit from a generic Callable Class such as a lambda type, there are two cases I can think of.
Create a Functor that calls a group of functors in a given inheritance sequence:
A simplified example:
template<typename TFirst, typename... TRemaining>
class FunctionSequence : public TFirst, FunctionSequence<TRemaining...>
{
public:
FunctionSequence(TFirst first, TRemaining... remaining)
: TFirst(first), FunctionSequence<TRemaining...>(remaining...)
{}
template<typename... Args>
decltype(auto) operator () (Args&&... args){
return FunctionSequence<TRemaining...>::operator()
( TFirst::operator()(std::forward<Arg>(args)...) );
}
};
template<typename T>
class FunctionSequence<T> : public T
{
public:
FunctionSequence(T t) : T(t) {}
using T::operator();
};
template<typename... T>
auto make_functionSequence(T... t){
return FunctionSequence<T...>(t...);
}
example usage:
int main(){
//note: these lambda functions are bug ridden. Its just for simplicity here.
//For correct version, see the one on coliru, read on.
auto trimLeft = [](std::string& str) -> std::string& { str.erase(0, str.find_first_not_of(' ')); return str; };
auto trimRight = [](std::string& str) -> std::string& { str.erase(str.find_last_not_of(' ')+1); return str; };
auto capitalize = [](std::string& str) -> std::string& { for(auto& x : str) x = std::toupper(x); return str; };
auto trimAndCapitalize = make_functionSequence(trimLeft, trimRight, capitalize);
std::string str = " what a Hullabaloo ";
std::cout << "Before TrimAndCapitalize: str = \"" << str << "\"\n";
trimAndCapitalize(str);
std::cout << "After TrimAndCapitalize: str = \"" << str << "\"\n";
return 0;
}
output
Before TrimAndCapitalize: str = " what a Hullabaloo "
After TrimAndCapitalize: str = "WHAT A HULLABALOO"
See it Live on Coliru
Create a Functor with an overloaded operator()(...), overloaded with all base classes' operator()(...):
Nir Friedman has already given a good instance of that in his answer to this question.
I have also drafted out a similar and simplified example, drawn from His. See it on Coliru
Jason Lucas also demonstrated its practical applications in his CppCon 2014 presentation "Polymorphism with Unions". You can find the Repo here, one of exact location in source code here (Thanks Cameron DaCamara)
Another cool trick: Since the resulting type from make_functionSequence(...) is a callable class. You can append more lambda's or callable to it at a later time.
//.... As previously seen
auto trimAndCapitalize = make_functionSequence(trimLeft, trimRight, capitalize);
auto replace = [](std::string& str) -> std::string& { str.replace(0, 4, "Whaaaaat"); return str; };
//Add more Functors/lambdas to the original trimAndCapitalize
auto replaced = make_functionSequence(trimAndCapitalize, replace /*, ... */);
replaced(str2);
Lambdas are function objects underneath, with additional syntatic sugar. a evaluates to something like that (with the MyLambda name being a random name, just like when you make namespace {} - namespace name will be random):
class MyLambda {
public:
void operator()() {
}
}
So when you inherit from a lambda, what you're doing is inheriting from an anonymous class / structure.
As for usefulness, well, it's as useful as any other inheritance. You can have the functionality of multiple lambdas with multiple inheritance in one object, you can add new methods to it to extend it. I can't think of any real application at the moment, but I'm sure there are many.
Refer to this question for more information.
This can actually be quite useful, but it depends how direct you want to be about the whole thing. Consider the following code:
#include <boost/variant.hpp>
#include <iostream>
#include <string>
#include <unordered_map>
template <class R, class T, class ... Ts>
struct Inheritor : public T, Inheritor<R, Ts...>
{
using T::operator();
using Inheritor<R, Ts...>::operator();
Inheritor(T t, Ts ... ts) : T(t), Inheritor<R, Ts...>(ts...) {}
};
template <class R, class T>
struct Inheritor<R, T> : public boost::static_visitor<R>, T
{
using T::operator();
Inheritor(T t) : T(t) {}
};
template <class R, class V, class ... T>
auto apply_visitor_inline(V& v, T ... t)
{
Inheritor<R, T...> i(t...);
return boost::apply_visitor(i, v);
}
int main()
{
boost::variant< int, std::string > u("hello world");
boost::variant< int, std::string > u2(5);
auto result = apply_visitor_inline<int64_t>(u, [] (int i) { return i;}, [] (const std::string& s) { return s.size();});
auto result2 = apply_visitor_inline<int64_t>(u2, [] (int i) { return i;}, [] (const std::string& s) { return s.size();});
std::cout << result;
std::cout << result2;
}
The snippet in your question does not show up in exact form anywhere. But you can see that the types of lambdas are being inferred in apply_visitor_inline. A class is then instantiated that inherits from all of these lambdas. The purpose? We are able to combine multiple lambdas into a single one, for the purpose of things like apply_visitor. This function expects to receive a single function object that defines multiple operator() and distinguish between them based on overloading. But sometimes it's more convenient to define a lambda that operates on each of the types we have to cover. In that case, inheritance from lambdas provides a mechanism for combining.
I got the inline visitor idea from here: https://github.com/exclipy/inline_variant_visitor, though I did not look at the implementation there, so this implementation is my own (but I guess its very similar).
Edit: the originally posted code only worked due to a bug in clang. According to this question (Overloaded lambdas in C++ and differences between clang and gcc), the lookup for multiple operator() in base classes is ambiguous, and indeed the code I posted originally did not compile in gcc. The new code compiles in both and should be compliant. Sadly, there is no way seemingly to do a variadic using statement, so recursion must be used.
Related
I created this class so I can have a value of any type which is either fixed or recalculated everytime it is used:
template <typename T>
class DynamicValue {
private:
std::variant<T, std::function<T()>> getter;
public:
DynamicValue(const T& constant) : getter(constant){};
template <typename F, typename = std::enable_if_t<std::is_invocable_v<F>>>
DynamicValue(F&& function) : getter(function) {}
DynamicValue(const T* pointer) : DynamicValue([pointer]() { return *pointer; }) {}
DynamicValue(const DynamicValue& value) : getter(value.getter) {}
~DynamicValue() {}
DynamicValue& operator=(const DynamicValue& value) {
getter = value.getter;
return *this;
}
operator T() {
return getter.index() == 0 ? std::get<T>(getter) : std::get<std::function<T()>>(getter)();
}
};
I also wrote the following dummy struct to showcase my issue:
struct A {
int b;
};
The problem is, ideally, I'd be able to treat any DynamicValue<T> as if it were of type T. So if I were to create a new value (DynamicValue<A> a = A{1};), I'd be able to do a.b and get the attribute b of the value calculated by a. However, I get the folowing error:
'class DynamicValue' has no member named 'b'
You can try a live example here.
My question is: is there anyway to overcome this issue, or must I accept the ((A) a).b syntax? I thought about overloading every operator to achieve my goal, but this solution wouldn't work with the . operator (and others), which is not overloadable, and might come with its own issues.
The problem is, ideally, I'd be able to treat any DynamicValue<T> as if it were of type T. So if I were to create a new value (DynamicValue<A> a = A{1};), I'd be able to do a.b and get the attribute b of the value calculated by a.
That would require either operator. overloading or delegated inheritance. Both are not available in C++.
I would recomment two models: operator() overloading or operator*.
Overloading the call operator will make your DynamicValue look like a function, whether it contains a function or a value:
DynamicValue<A> a = A{1};
auto real_a = a();
std::cout << real_a.b;
If you overload the dereference operator, your class would look like a pointer to a value, whether it's a value or a function:
DynamicValue<A> a = A{1};
auto real_a = *a;
std::cout << real_a.b;
I would be careful with operator-> since it may induce significant performance degradation if your dynamic value contains a function.
I would completely avoid implicit conversion operators since it comes with a lot of caveat and gotcha. It's a great footgun and must be implemented with caution.
I wrote some code S s; ... s = {};, expecting it to end up the same as S s = {};. However it didn't. The following example reproduces the problem:
#include <iostream>
struct S
{
S(): a(5) { }
S(int t): a(t) {}
S &operator=(int t) { a = t; return *this; }
S &operator=(S const &t) = default;
int a;
};
int main()
{
S s = {};
S t;
t = {};
std::cout << s.a << '\n';
std::cout << t.a << '\n';
}
The output is:
5
0
My questions are:
Why is operator=(int) selected here, instead of "ambiguous" or the other one?
Is there a tidy workaround, without changing S?
My intent is s = S{}; . Writing s = {}; would be convenient if it worked. I'm currently using s = decltype(s){}; however I'd prefer to avoid repeating the type or the variable name.
Why is operator=(int) selected here, instead of "ambiguous" or the other one?
{} to int is the identity conversion ([over.ics.list]/9). {} to S is a user-defined conversion ([over.ics.list]/6) (technically, it's {} to const S&, and goes through [over.ics.list]/8 and [over.ics.ref] first before coming back to [over.ics.list]/6).
The first wins.
Is there a tidy workaround?
A variation of the trick std::experimental::optional pulls to make t = {} always make t empty.
The key is to make operator=(int) a template. If you want to accept int and only int, then it becomes
template<class Int, std::enable_if_t<std::is_same<Int, int>{}, int> = 0>
S& operator=(Int t) { a = t; return *this; }
Different constraints can be used if you want to enable conversions (you'd probably also want to take the argument by reference in that case).
The point is that by making the right operand's type a template parameter, you block t = {} from using this overload - because {} is a non-deduced context.
...without changing S?
Does template<class T> T default_constructed_instance_of(const T&) { return {}; } and then s = default_constructed_instance_of(s);count?
First of all, the case has nothing to do with the "int" version of the assignment operator, you can just delete it. You can actually delete the other assignment operator too as it will be generated by the compiler. IE this kind of type automatically receives copy/move constructors and the assignment operator. (ie they are not prohibited and you are just repeating what the compiler does automatically with explicit notation)
The first case
uses copy initialization:
S s = {}; // the default constructor is invoked
That is a post-construction copy assignment, yet compilers optimize such simple cases. You should use direction initialization instead:
S s{}; // the default constructor is invoked (as you have it)
Note, you can also write:
S s; // the default constructor is invoked if you have it
The second case
What you should write is direct initialization of the right hand side of the copy assignment:
t = S{};
This notation will invoke the default constructor (if there is one), or value initialization for the members (as long as the type is an aggregate). Here is the relevant info: http://en.cppreference.com/w/cpp/language/value_initialization
I'm trying to declare a class "Lambdas" that would provide lambdas (and their type information) to another class "Test". Lambdas also is holding the "this" reference to concrete Test instance for access of Test public members, inside the lambdas.
I do it to define the lambdas once and then to deduce types anywhere else through decltype()
But I get error: Member access to incomplete type:
template <typename T>
struct LambdasInstances {
T * self;
explicit LambdasInstances(T * p) : self(p) {} // CAPTURE Test "this"
auto genLambda1() {
return [=](int x){
self->testVar; // ERROR: Member access to incomplete type
};
}
};
class Test3 {
public:
LambdasInstances<Test3> instances;
int testVar;
Test3() : instances(this) {}
decltype(instances.genLambda1()) varLambda = instances.genLambda1();
void useLambda() { varLambda(123); }
};
BUT IF I would make genLambda() externally defined, then I would run to another problem - ERROR: genLambda() with deduced type cannot be used before its defined!:
template <typename T>
struct LambdasInstances {
T * self;
explicit LambdasInstances(T * p) : self(p) {}
auto genLambda1(); // would be defined after Test3 declaration
};
class Test3 {
public:
int testVar;
LambdasInstances<Test3> instances;
Test3() : instances(this) {}
decltype(instances.genLambda1()) varLambda = instances.genLambda1();
};
// IF WE DEFINE AFTER :: ^ genLambda() with deduced type cannot be used before its defined!
template< typename T>
auto LambdasInstances<T>::genLambda1() {
return [=](int x){
self->testVar;
};
}
The compiler might require the definition of the whole type available to be able to know the offset of the members (e.g. in the expression self->testVar, the compiler has to know the offset of testVar), but it might not be able to know the offset of a particular member until it will get the whole definition, because the compiler must know the alignment of your structure/class (I would even guess that some not straight forward logic might be involved when computing the padding between members) that comes after the knowledge of all members, see this, that is totally compiler and platform specific.
So back to your problem. You tell the compiler to define Test3 with genLambda1 as a member, that is a lambda that has to know the offset of member testVar. Seems easy, right? But the offset of testVar depends on the definition of the whole Test3 (see the paragraph above) - here we are in the loop.
You would say: "Hey stupid compiler, I give only a pointer to the lambda, not a copy by value where you have to know the whole size of the `Test3, why would you stop me from doing that?". Quite a legit question because theoretically compiler can resolve offset later, but seems like the compilers are not smart enough. And the standard says:
The lambda-expression’s compound-statement yields the function-body (8.4) of the function call operator ...
That basically says that the lambda body is the function body, but in the function body you cannot have incomplete types right? Lambdas are relatively new to C++ and not all corner cases are elaborated, so let's hope that in some future this will be resolved, of course the compilers will be more complicated as well as the standard.
For you problem I see the following resolution:
template <typename T>
struct LambdasInstances {
explicit LambdasInstances(T* p) : _lambda([=](int x) { return p->testVar; }) {}
auto genLambda1() { return _lambda; }
private:
std::function<void(int)> _lambda;
};
class Test3 {
public:
int testVar;
LambdasInstances<Test3> instances;
Test3() : instances(this) {}
decltype(instances.genLambda1()) varLambda = instances.genLambda1();
};
int main() {
Test3 test3;
Test3* test3_ptr;
LambdasInstances<Test3> instances(&test3);
auto lambda = [=](int x) { return test3_ptr->testVar; };
std::function<void(int)> functor = lambda;
cerr << sizeof(Test3) << endl;
cerr << sizeof(LambdasInstances<Test3>) << endl;
cerr << sizeof(lambda) << endl;
cerr << sizeof(functor) << endl;
return 0;
}
The difference is that std::function gives you a level of abstraction that protects the type LambdasInstances::genLambda1 from the definition of Test3. Unfortunately, as you will see from the main output the function takes more memory than the lambda. If this does not satisfy your needs I recommend to revise the design and may be you will find something in the old good techniques before the era of lambdas.
Imagine you have a number of overloaded methods that (before C++11) looked like this:
class MyClass {
public:
void f(const MyBigType& a, int id);
void f(const MyBigType& a, string name);
void f(const MyBigType& a, int b, int c, int d);
// ...
};
This function makes a copy of a (MyBigType), so I want to add an optimization by providing a version of f that moves a instead of copying it.
My problem is that now the number of f overloads will duplicate:
class MyClass {
public:
void f(const MyBigType& a, int id);
void f(const MyBigType& a, string name);
void f(const MyBigType& a, int b, int c, int d);
// ...
void f(MyBigType&& a, int id);
void f(MyBigType&& a, string name);
void f(MyBigType&& a, int b, int c, int d);
// ...
};
If I had more parameters that could be moved, it would be unpractical to provide all the overloads.
Has anyone dealt with this issue? Is there a good solution/pattern to solve this problem?
Thanks!
Herb Sutter talks about something similar in a cppcon talk
This can be done but probably shouldn't. You can get the effect out using universal references and templates, but you want to constrain the type to MyBigType and things that are implicitly convertible to MyBigType. With some tmp tricks, you can do this:
class MyClass {
public:
template <typename T>
typename std::enable_if<std::is_convertible<T, MyBigType>::value, void>::type
f(T&& a, int id);
};
The only template parameter will match against the actual type of the parameter, the enable_if return type disallows incompatible types. I'll take it apart piece by piece
std::is_convertible<T, MyBigType>::value
This compile time expression will evaluate to true if T can be converted implicitly to a MyBigType. For example, if MyBigType were a std::string and T were a char* the expression would be true, but if T were an int it would be false.
typename std::enable_if<..., void>::type // where the ... is the above
this expression will result in void in the case that the is_convertible expression is true. When it's false, the expression will be malformed, so the template will be thrown out.
Inside the body of the function you'll need to use perfect forwarding, if you are planning on copy assigning or move assigning, the body would be something like
{
this->a_ = std::forward<T>(a);
}
Here's a coliru live example with a using MyBigType = std::string. As Herb says, this function can't be virtual and must be implemented in the header. The error messages you get from calling with a wrong type will be pretty rough compared to the non-templated overloads.
Thanks to Barry's comment for this suggestion, to reduce repetition, it's probably a good idea to create a template alias for the SFINAE mechanism. If you declare in your class
template <typename T>
using EnableIfIsMyBigType = typename std::enable_if<std::is_convertible<T, MyBigType>::value, void>::type;
then you could reduce the declarations to
template <typename T>
EnableIfIsMyBigType<T>
f(T&& a, int id);
However, this assumes all of your overloads have a void return type. If the return type differs you could use a two-argument alias instead
template <typename T, typename R>
using EnableIfIsMyBigType = typename std::enable_if<std::is_convertible<T, MyBigType>::value,R>::type;
Then declare with the return type specified
template <typename T>
EnableIfIsMyBigType<T, void> // void is the return type
f(T&& a, int id);
The slightly slower option is to take the argument by value. If you do
class MyClass {
public:
void f(MyBigType a, int id) {
this->a_ = std::move(a); // move assignment
}
};
In the case where f is passed an lvalue, it will copy construct a from its argument, then move assign it into this->a_. In the case that f is passed an rvalue, it will move construct a from the argument and then move assign. A live example of this behavior is here. Note that I use -fno-elide-constructors, without that flag, the rvalue cases elides the move construction and only the move assignment takes place.
If the object is expensive to move (std::array for example) this approach will be noticeably slower than the super-optimized first version. Also, consider watching this part of Herb's talk that Chris Drew links to in the comments to understand when it could be slower than using references. If you have a copy of Effective Modern C++ by Scott Meyers, he discusses the ups and downs in item 41.
You may do something like the following.
class MyClass {
public:
void f(MyBigType a, int id) { this->a = std::move(a); /*...*/ }
void f(MyBigType a, string name);
void f(MyBigType a, int b, int c, int d);
// ...
};
You just have an extra move (which may be optimized).
My first thought is that you should change the parameters to pass by value. This covers the existing need to copy, except the copy happens at the call point rather than explicitly in the function. It also allows the parameters to be created by move construction in a move-able context (either unnamed temporaries or by using std::move).
Why you would do that
These extra overloads only make sense, if modifying the function paramers in the implementation of the function really gives you a signigicant performance gain (or some kind of guarantee). This is hardly ever the case except for the case of constructors or assignment operators. Therefore, I would advise you to rethink, whether putting these overloads there is really necessary.
If the implementations are almost identical...
From my experience this modification is simply passing the parameter to another function wrapped in std::move() and the rest of the function is identical to the const & version. In that case you might turn your function into a template of this kind:
template <typename T> void f(T && a, int id);
Then in the function implementation you just replace the std::move(a) operation with std::forward<T>(a) and it should work. You can constrain the parameter type T with std::enable_if, if you like.
In the const ref case: Don't create a temporary, just to to modify it
If in the case of constant references you create a copy of your parameter and then continue the same way the move version works, then you may as well just pass the parameter by value and use the same implementation you used for the move version.
void f( MyBigData a, int id );
This will usually give you the same performance in both cases and you only need one overload and implementation. Lots of plusses!
Significantly different implementations
In case the two implementations differ significantly, there is no generic solution as far as I know. And I believe there can be none. This is also the only case, where doing this really makes sense, if profiling the performance shows you adequate improvements.
You might introduce a mutable object:
#include <memory>
#include <type_traits>
// Mutable
// =======
template <typename T>
class Mutable
{
public:
Mutable(const T& value) : m_ptr(new(m_storage) T(value)) {}
Mutable(T& value) : m_ptr(&value) {}
Mutable(T&& value) : m_ptr(new(m_storage) T(std::move(value))) {}
~Mutable() {
auto storage = reinterpret_cast<T*>(m_storage);
if(m_ptr == storage)
m_ptr->~T();
}
Mutable(const Mutable&) = delete;
Mutable& operator = (const Mutable&) = delete;
const T* operator -> () const { return m_ptr; }
T* operator -> () { return m_ptr; }
const T& operator * () const { return *m_ptr; }
T& operator * () { return *m_ptr; }
private:
T* m_ptr;
char m_storage[sizeof(T)];
};
// Usage
// =====
#include <iostream>
struct X
{
int value = 0;
X() { std::cout << "default\n"; }
X(const X&) { std::cout << "copy\n"; }
X(X&&) { std::cout << "move\n"; }
X& operator = (const X&) { std::cout << "assign copy\n"; return *this; }
X& operator = (X&&) { std::cout << "assign move\n"; return *this; }
~X() { std::cout << "destruct " << value << "\n"; }
};
X make_x() { return X(); }
void fn(Mutable<X>&& x) {
x->value = 1;
}
int main()
{
const X x0;
std::cout << "0:\n";
fn(x0);
std::cout << "1:\n";
X x1;
fn(x1);
std::cout << "2:\n";
fn(make_x());
std::cout << "End\n";
}
This is the critical part of the question:
This function makes a copy of a (MyBigType),
Unfortunately, it is a little ambiguous. We would like to know what is the ultimate target of the data in the parameter. Is it:
1) to be assigned to an object that existing before f was called?
2) or instead, stored in a local variable:
i.e:
void f(??? a, int id) {
this->x = ??? a ???;
...
}
or
void f(??? a, int id) {
MyBigType a_copy = ??? a ???;
...
}
Sometimes, the first version (the assignment) can be done without any copies or moves. If this->x is already long string, and if a is short, then it can efficiently reuse the existing capacity. No copy-construction, and no moves. In short, sometimes assignment can be faster because we can skip the copy contruction.
Anyway, here goes:
template<typename T>
void f(T&& a, int id) {
this->x = std::forward<T>(a); // is assigning
MyBigType local = std::forward<T>(a); // if move/copy constructing
}
If the move version will provide any optimization then the implementation of the move overloaded function and the copy one must be really different. I don't see a way to get around this without providing implementations for both.
Herb Sutter asked this question in a talk about C++11 and concurrency (See this video)
The key idea here is to have a non locking class X where every function call should be decorated with a lock that is unlocked after a function.
However, Herb Sutter drifts then off and presents a functor based approach. I'm wondering if it is even possible with C++11 to wrap each function call with lock and unlock of a class in a generic way (not wrapping every function call manually).
class X {
public:
X() = default;
void somefunc(arg1 x1, arg2 x2, ...);
void somefunc2(arg1 x1, arg2 x2, ...);
/* and more */
};
// herb admits one way to make all functions *available*
// in another class is by derivation
class XX : public X {
public:
XX() = default;
// all functions available in NON overloaded form...
};
there is also the decorator pattern
class XXX {
public:
XXX(X &x) : m_x(x) {}
// explicitly call each wrapped function ... done for each class separately.
void somefunc(arg1 x1, arg2 x2, ...);
void somefunc2(arg1 x1, arg2 x2, ...);
private:
class X& m_x;
};
but is there something like this possible:
template<>
class wrap_everything;
wrap_everything<X> x;
x.somefunc(x1,x2,...); // this is then locked.
for the sake of completeness this is herb sutter's functor based approach:
template <class T> class locker {
private:
mutable T m_t;
mutable std::mutex m_m;
public:
locker( T t = T{} ) : m_t(t) {}
template <typename F>
auto operator()(F f) const -> decltype(f(m_t)) {
std::lock_guard<mutex> _{m_m};
return f(t);
}
};
// usage
locker<std::string> s;
s([](string &s) {
s += "foobar";
s += "barfoo";
});
The question is about the EXECUTE-AROUND pattern. I made a generic (but only barely tested) implementation of EXECUTE-AROUND POINTER at https://gitlab.com/redistd/redistd/blob/master/include/redi/exec_around.h
This allows:
struct X { void f() { } };
auto x = mutex_around<X>();
x->f(); // locks a mutex for duration of call to X::f
A more in depth explaination on how the family of execute around patterns work can be found here (pdf)
I don't believe there is a portable generic way to do this in current C++. If templates were capable of taking an overload set as a template parameter (which I'd very much like to see in C++14 for many reasons), and the call site could be changed from x.y(z) to x->y(z), I think it could probably be done with a proxy and an overloaded operator->. Otherwise, the best generic way of doing something like this is using Aspect Oriented Programming frameworks for C++ (such as AspectC++).
Being able to wrap each member function call is only really half the story on this, though. According to the Interface Principle, the interface of a class is the functions that mention a class and are supplied with a class. This includes public member functions, friend functions, and free functions in the same namespace as the class. Being able to pass instances to such functions in a wrapped way is a much more subtle problem than merely wrapping member function calls, which is where Sutter's approach shows real power and flexibility.
It is not possible to do exactly what you want, but something close is doable.
#include <iostream>
class Foo {
public:
void one (int x) {
std::cout << "Called Foo::one(" << x << ")\n";
}
void two (int x, double y) {
std::cout << "Called Foo::two(" << x << ", " << y << ")\n";
}
};
class ScopeDecorator {
public:
ScopeDecorator() {
std::cout << "Enter scope\n";
}
~ScopeDecorator() {
std::cout << "Exit scope\n";
}
};
template <class Wrappee, class Wrapper>
class Wrap {
public:
Wrap (Wrappee& w) : wrappee(w) {}
template <typename rettype, typename... argtype>
rettype call (rettype (Wrappee::*func)(argtype...), argtype... args)
{
Wrapper wrapper;
return (wrappee.*func)(args...);
}
private:
Wrappee& wrappee;
};
int main ()
{
Foo foo;
Wrap<Foo, ScopeDecorator> wfoo(foo);
wfoo.call(&Foo::one, 42);
wfoo.call(&Foo::two, 32, 3.1415);
}
For anyone interested, I also wrote a generic implementation of the execute around idom:
https://github.com/ArnaudBienner/ExecuteAround
https://github.com/ArnaudBienner/ExecuteAround/blob/master/ExecuteAround.h
with an example on how to make a thread safe object from it:
https://github.com/ArnaudBienner/ExecuteAround/blob/master/main.cpp#L78
Just for the record, since the one provided by Jonathan already looks great, and mine probably needs some clean up.
It is entirely possible and it was proposed long back by none other than Stroustrup and his original proposal is still available. See www.stroustrup.com/wrapper.pdf
Basically the idea is to override operator -> at 2 levels and lock/unlock mutex in the constructor and destructor of temporary object that is returned by first operator ->.
The second operator -> will return the pointer of object on which the method will be invoked.