Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Mach7 with variant: cannot access the matched sub-object #32

Open
akrzemi1 opened this issue Feb 11, 2016 · 4 comments
Open

Mach7 with variant: cannot access the matched sub-object #32

akrzemi1 opened this issue Feb 11, 2016 · 4 comments
Labels

Comments

@akrzemi1
Copy link
Contributor

I am using the library to switch on boost::variant and inspect/modify a given sub-type, as per the example below.

This doesn't work, because (to my knowedge) there is no way to get access to a mutable A from an instance of var<A&>.

Would it be possible to extend the interface of mch::var to get mutating access to its contained value?

#include <boost/variant.hpp>
#include <Mach7/code/type_switchN-patterns-xtl.hpp>
#include <Mach7/code/adapters/boost/adapt_boost_variant.hpp>
#include <Mach7/code/patterns/constructor.hpp>
#include <Mach7/code/patterns/primitive.hpp>

struct A
{
    int ma;
};
using V = boost::variant<A>;

void mutate_member(V& v)
{
    mch::var<A&> a;

    Match (v)
    {
        Case(mch::C<A>(a))
             a.ma = 2; // ERROR: cannot mutate a subobject of A
    }
    EndMatch
}

int main() {}
akrzemi1 added a commit to akrzemi1/Mach7 that referenced this issue Feb 24, 2016
@solodon4
Copy link
Owner

Here is how your broader mutating example from https://github.com/akrzemi1/__sandbox__/blob/master/mach7_with_variant.md can be written in Mach7 in the way typically done in other languages:

struct TankA { int va = 0; };
struct TankB { int vb = 0; };
struct TankX { };
using  Tank = boost::variant<TankA, TankB, TankX>;

namespace mch ///< Mach7 library namespace
{
template <> struct bindings<TankA> { Members(TankA::va); };
template <> struct bindings<TankB> { Members(TankB::vb); };
} // of namespace mch

int read(Tank const& tank)
{
  using namespace mch;

  var<const int&> v; // You create a reference to bind to a subcomponent

  Match(tank)
  {
    Case(C<TankA>(v)) return v;      // Once bound, you simply use it in the RHS
    Case(C<TankB>(v)) return v + 10;
    Case(C<TankX>())  return -1;
  }
  EndMatch
}

int write(Tank& tank)
{
  using namespace mch;

  var<int&> v;

  Match(tank)
  {
    Case(C<TankA>(v)) v = 1;  return v; // NOTE: You can also modify value bound via reference to a subcomponent
    Case(C<TankB>(v)) v = 42; return 0;
    Case(C<TankX>())  return -1;
  }
  EndMatch
}

int main()
{
    Tank t = TankB();
    assert (read(t) == 10);
    write(t);
    TankB* ptb = boost::get<TankB>(&t); 
    assert(ptb && ptb->vb == 42);
}

@akrzemi1
Copy link
Contributor Author

Thank you. That is quite interesting, and I start to see the expressiveness of the library. But let me change the problem a bit. Suppose all members of my types are private, and can only be accessed via public member functions. See "Challenge 2" in the same file: https://github.com/akrzemi1/__sandbox__/blob/master/mach7_with_variant.md

@akrzemi1
Copy link
Contributor Author

Whoa! I have just realized you can teach it to recognize member functions (getters). Impressive!

@solodon4
Copy link
Owner

Yes, Members() macro accepts data members, nullary member functions and unary free-standing functions with the argument taking class as an argument. An example of the latter can be seen here:

https://github.com/solodon4/Mach7/blob/master/code/test/unit/example05.cpp#L67-L69

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
Projects
None yet
Development

No branches or pull requests

2 participants