0

In this tutorial they state:

A strong reason to use generic lambdas is for visiting syntax.

boost::variant<int, double> value;
apply_visitor(value, [&](auto&& e){
  std::cout << e;
});

Here we are visiting in a polymorphic manner; but in other contexts, the names of the type we are passing isn't interesting:

mutex_wrapped<std::ostream&> os = std::cout;
os.write([&](auto&& os){
  os << "hello world\n";
});

Repeating the type of std::ostream& is noise here; it would be like having to mention the type of a variable every time you use it. Here we are creating a visitor, but no a polymorphic one; auto is used for the same reason you might use auto in a for(:) loop.

First of all I could not get the above example to work with out swapping the operands around:

boost::variant<int, double> value;
boost::apply_visitor(
    [&](auto&& e){
        std::cout << e;
    },
    value
);

I suppose this could be due to changes to boost since the tutorial was written.

But for the second example I cannot yet find from where mutex_wrapped comes, and I do not understand what write(lambda) will do, it seems to me that write() requires const char* s, streamsize n.

Is this second example purely imaginary as in mutex_wrapped is an imaginary class that has a write method that takes a lambda and executes the lambda using the wrapped stream as the parameter?

Motomotes
  • 4,111
  • 1
  • 25
  • 24
  • `mutex_wrapped` is quite clearly a general wrapper around an object. `write` is not related to `ostream` in particular but a call to the operation on the managed object. `write` will supply the object by reference, while `read` supplies by const reference. Also all read/writes internally lock/unlock the mutex. – ALX23z May 11 '23 at 03:50
  • @Motomotes Why have you changed your decision and accepted the answer that can't be compiled with the code in your question? The error is: `error: no viable conversion from 'ostream' (aka 'basic_ostream') to 'mutex_wrapped' (aka 'mutex_wrapped &>')\n mutex_wrapped os = std::cout;` That answer changed your code to `mutex_wrapped os(std::cout);` – 273K May 11 '23 at 05:15
  • The other answer was first and made the needed correction to the example, `mutex_wrapped os(std::cout);` – Motomotes May 11 '23 at 05:17

2 Answers2

0

Declaimer of that site:

This Tutorial is compiled from StackOverflow Documentation, the content is written by the brilliant people at Stack Overflow.

Googling trough StackOverflow gave me that posted answer: https://stackoverflow.com/a/59601498/6752050. It defined shared_mutex_wrapped but the example used it as mutex_wrapped, it might be a typo. Let's name it mutex_wrapped:

template<class T>
struct mutex_wrapped {
  mutex_wrapped(T t) : t(t) {}  // Was missing in the original post

  template<class F>
  auto read( F&& f ) const {
    auto l = lock();
    return f(t);
  }

  template<class F>
  auto write( F&& f ) {
    auto l = lock();
    return f(t);
  }

private:
  mutable std::shared_mutex m;
  T t = {};
  auto lock() const { return std::shared_lock< std::shared_mutex >( m ); }
  auto lock() { return std::unique_lock< std::shared_mutex >( m ); }
};
273K
  • 29,503
  • 10
  • 41
  • 64
  • Thanks, I saw that briefly from searching earlier but noticed it was `shared_mutex_wrapper`, yet it was used as `mutex_wrapper` in the example on the other answer as well, so I went ahead and tried it but it gives an error like "no viable conversion between basic_stream... and mutex_wrapper..." So even with the above definition the example still does not work. – Motomotes May 11 '23 at 04:43
  • Because it is missing a constructor, that you could easy add. See the update. – 273K May 11 '23 at 04:48
0

The Wrapper needs a generic constructor to assign it's internal type T, t variable. Here's a complete corrected example:

#include <iostream>
#include <mutex>
#include <shared_mutex>
    
template<class T>
struct mutex_wrapped {
    explicit mutex_wrapped(T t) : t(t) {}

    template<class F>
    auto read( F&& f ) const {
        auto l = lock();
        return f(t);
    }
    template<class F>
    auto write( F&& f ) {
        auto l = lock();
        return f(t);
    }
private:
    mutable std::shared_mutex m;
    T t = {};
    auto lock() const { return std::shared_lock< std::shared_mutex >( m ); }
    auto lock() { return std::unique_lock< std::shared_mutex >( m ); }
};

int main() {
    mutex_wrapped<std::ostream&> os(std::cout);
    os.write([&](auto&& os){
        os << "hello world\n";
    });

    return 0;
}

1 2

  • Even copying and fixing another answer, you managed to insert absolutely unnecessary [`using namespace std;` that is considered bad practice](https://stackoverflow.com/questions/1452721/why-is-using-namespace-std-considered-bad-practice). – 273K May 11 '23 at 04:53
  • @273K My answer was submitted 5 seconds prior to one's edit containing the constructor, I tried the example in CLion which includes using...std in the default project template. – Thomas Stillwell May 11 '23 at 05:01