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

Problem with std::unique_ptr #67

Closed
forflo opened this issue Jul 19, 2016 · 2 comments
Closed

Problem with std::unique_ptr #67

forflo opened this issue Jul 19, 2016 · 2 comments
Assignees
Labels

Comments

@forflo
Copy link

forflo commented Jul 19, 2016

example04-smart-ptr.cpp demonstrates how one can match on unique_ptr values. The example, however only describes the usage of adapter aided matching using the reference operator. Below that, there is another example showing an alternate matching technique:

//...
// previous example
#else
int evl(const Expr& e)
{
    var<ExprPtr> e1, e2;
    var<int> n;

    Match(e)
    {
        Case(C<Value> (n)    ) return n;
        Case(C<Plus>  (e1,e2)) return evl(*e1) + evl(*e2);
        Case(C<Minus> (e1,e2)) return evl(*e1) - evl(*e2);
        Case(C<Times> (e1,e2)) return evl(*e1) * evl(*e2);
        Case(C<Divide>(e1,e2)) return evl(*e1) / evl(*e2);
    }
    EndMatch

    XTL_UNREACHABLE; // To avoid warning that control may reach end of a non-void function
}
#endif

The code snippet pasted above does not compile. However, that's exactly what I need, as I cannot use references in my current context.

Is there any way to get the desired behaviour to work?

@solodon4
Copy link
Owner

solodon4 commented Jul 26, 2016

Sorry for delay with an answer - was on a small vacation.

The main problem here is that std::unique_ptr is a non-copyable type. When you declare var you essentially declare a variable that will hold a value of type ExprPtr, that value will be assigned from the value of the subject during matching and since the subject is of non-assignable type, you get an error.

To avoid copying std::unique_ptr, you can try to bind by reference that smart pointer, however in current C++ this will become ugly for the RHS as there is no real way of creating perfect proxy:

int evl(const Expr& e)
{
    var<const ExprPtr&> e1, e2;
    var<int> n;

    Match(e)
    {
        Case(C<Value> (n)    ) return n;
        Case(C<Plus>  (e1,e2)) return evl(*e1.m_value->get()) + evl(*e2.m_value->get());
        Case(C<Minus> (e1,e2)) return evl(*e1.m_value->get()) - evl(*e2.m_value->get());
        Case(C<Times> (e1,e2)) return evl(*e1.m_value->get()) * evl(*e2.m_value->get());
        Case(C<Divide>(e1,e2)) return evl(*e1.m_value->get()) / evl(*e2.m_value->get());
    }
    EndMatch

    XTL_UNREACHABLE; // To avoid warning that control may reach end of a non-void function
}

You can also make it a bit prettier by changing bindings to retrieve the pointer from the underlaying unique_ptr. Just remember here that arguments to Members macro can be either:

  • pointers to data members
  • pointers to nullary member functions
  • pointers to unary functions taking subject as an argument and returning extracted part.

It's the last one we use here (only provide specializations for const case, you can derive similar for non-const):

template <typename C>
const Expr* get_e1(const C* subject)
{
    return subject->e1.get(); // Notice call to get on std::unique_ptr here
}

template <typename C>
const Expr* get_e2(const C* subject)
{
    return subject->e2.get();
}

namespace mch ///< Mach7 library namespace
{
template <> struct bindings<Value> { Members(Value::value); };
template <> struct bindings<Plus>  { Members(get_e1<Plus>  , get_e2<Plus>);   };
template <> struct bindings<Minus> { Members(get_e1<Minus> , get_e2<Minus>);  };
template <> struct bindings<Times> { Members(get_e1<Times> , get_e2<Times>);  };
template <> struct bindings<Divide>{ Members(get_e1<Divide>, get_e2<Divide>); };
} // of namespace mch

with these bindings you can simply write:

int evl(const Expr& e)
{
    var<const Expr*> e1, e2; // Note we don't bind std::unique_ptr here, which is non-copyable, but its pointer's value
    var<int> n;

    Match(e)
    {
        Case(C<Value> (n)    ) return n;
        Case(C<Plus>  (e1,e2)) return evl(*e1) + evl(*e2);
        Case(C<Minus> (e1,e2)) return evl(*e1) - evl(*e2);
        Case(C<Times> (e1,e2)) return evl(*e1) * evl(*e2);
        Case(C<Divide>(e1,e2)) return evl(*e1) / evl(*e2);
    }
    EndMatch

    XTL_UNREACHABLE; // To avoid warning that control may reach end of a non-void function
}

Is that closer to what you are looking for? I added file example04-smart-ptr-bind-ptr.cpp demonstrating it - compare it to the original example for differences.

@solodon4 solodon4 self-assigned this Jul 26, 2016
@forflo
Copy link
Author

forflo commented Jul 29, 2016

Is that closer to what you are looking for?

Much closer, thank you!

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