Skip to content

How to use with templated classes? #67

@jagot

Description

@jagot

Thank you for this interesting library!

I am trying to reproduce the example in the documentation, but with a templated type hierarchy.

Without templates

First, my version of the example without templates:

#include <iostream>
#include <memory>

#include <boost/openmethod.hpp>
#include <boost/openmethod/initialize.hpp>
#include <boost/openmethod/interop/std_shared_ptr.hpp>

using boost::openmethod::virtual_ptr;
using namespace boost::openmethod::aliases;

struct Node {};

struct Variable : Node {
  int v;
  Variable(int v) : v(v) {}
};

struct Plus : Node {
  shared_virtual_ptr<Node> left, right;
  Plus(shared_virtual_ptr<Node> left, shared_virtual_ptr<Node>right)
    : left(left), right(right) {}
};

struct Times : Node {
  shared_virtual_ptr<Node> left, right;
  Times(shared_virtual_ptr<Node> left, shared_virtual_ptr<Node>right)
    : left(left), right(right) {}
};


BOOST_OPENMETHOD(value, (virtual_ptr<const Node> node), int);

BOOST_OPENMETHOD_OVERRIDE(value, (virtual_ptr<const Variable> var), int) {
  return var->v;
}

BOOST_OPENMETHOD_OVERRIDE(value, (virtual_ptr<const Plus> plus), int) {
  return value(plus->left) + value(plus->right);
}

BOOST_OPENMETHOD_OVERRIDE(value, (virtual_ptr<const Times> times), int) {
  return value(times->left) * value(times->right);
}

BOOST_OPENMETHOD_CLASSES(Node, Variable, Plus, Times);

int main(int argc, char* argv[]) {
  boost::openmethod::initialize();

  shared_virtual_ptr<Node> a = make_shared_virtual<Variable>(2),
    b = make_shared_virtual<Variable>(3),
    c = make_shared_virtual<Variable>(4),
    d = make_shared_virtual<Plus>(a, b),
    e = make_shared_virtual<Times>(d, c);


  std::cout << "a = " << value(a) << std::endl;
  std::cout << "b = " << value(b) << std::endl;
  std::cout << "c = " << value(c) << std::endl;

  std::cout << "d = " << value(d) << std::endl;
  std::cout << "e = " << value(e) << std::endl;

  return 0;
}

This outputs

a = 2
b = 3
c = 4
d = 5
e = 20

as expected.

With templates

#include <iostream>
#include <memory>

#include <boost/openmethod.hpp>
#include <boost/openmethod/initialize.hpp>
#include <boost/openmethod/interop/std_shared_ptr.hpp>
#include <boost/openmethod/macros.hpp>

using boost::openmethod::method;
using boost::openmethod::use_classes;
using boost::openmethod::virtual_ptr;
using namespace boost::openmethod::aliases;

template<typename T>
struct Node {};

template<typename T>
struct Variable : Node<T> {
  T v;
  Variable(T v) : v(v) {}
};

template<typename T>
struct Plus : Node<T> {
  shared_virtual_ptr<Node<T>> left, right;
  Plus(shared_virtual_ptr<Node<T>> left, shared_virtual_ptr<Node<T>>right)
    : left(left), right(right) {}
};

template<typename T>
struct Times : Node<T> {
  shared_virtual_ptr<Node<T>> left, right;
  Times(shared_virtual_ptr<Node<T>> left, shared_virtual_ptr<Node<T>>right)
    : left(left), right(right) {}
};

struct BOOST_OPENMETHOD_ID(value);

template<typename T>
using value = method<BOOST_OPENMETHOD_ID(value),
                     T(virtual_ptr<const Node<T>> node)>;

template<typename T>
T variable_value(virtual_ptr<const Variable<T>> var) {
  return var->v;
}

template<typename T>
T plus_value(virtual_ptr<const Plus<T>> plus) {
  return value(plus->left) + value(plus->right);
}

template<typename T>
T times_value(virtual_ptr<const Times<T>> times) {
  return value(times->left) * value(times->right);
}

// Compile fails with "error: expected unqualified-id"
template<typename T>
static value<T>::override<variable_value<T>> override_variable_value;
template<typename T>
static value<T>::override<plus_value<T>> override_plus_value;
template<typename T>
static value<T>::override<times_value<T>> override_times_value;

#define NODE_IMPL(T, NAME) \
use_classes<Node<T>, Variable<T>, Plus<T>, Times<T>> NAME;

NODE_IMPL(float, float_node_classes);

int main(int argc, char* argv[]) {
  boost::openmethod::initialize();

  shared_virtual_ptr<Node<float>> a = make_shared_virtual<Variable<float>>(2),
    b = make_shared_virtual<Variable<float>>(3),
    c = make_shared_virtual<Variable<float>>(4),
    d = make_shared_virtual<Plus<float>>(a, b),
    e = make_shared_virtual<Times<float>>(d, c);

  std::cout << "a = " << value<float>::fn(a) << std::endl;
  std::cout << "b = " << value<float>::fn(b) << std::endl;
  std::cout << "c = " << value<float>::fn(c) << std::endl;

  std::cout << "d = " << value<float>::fn(d) << std::endl;
  std::cout << "e = " << value<float>::fn(e) << std::endl;

  return 0;
}

This does not compile, as indicated by the comment in the code:

/usr/bin/c++ -DBOOST_CONTAINER_NO_LIB -DBOOST_JSON_NO_LIB -DFMT_SHARED -isystem /opt/homebrew/include -std=c++2b -arch arm64 -fcolor-diagnostics -Werror=return-type -Werror=switch -MD -MT CMakeFiles/templated.dir/templated.cpp.o -MF CMakeFiles/templated.dir/templated.cpp.o.d -o CMakeFiles/templated.dir/templated.cpp.o -c /Users/jagot/work/projects/examples/boost-openmethods/templated.cpp
/Users/jagot/work/projects/examples/boost-openmethods/templated.cpp:49:26: error: expected unqualified-id
   49 | static value<T>::override<variable_value<T>> override_variable_value;
      |                          ^
/Users/jagot/work/projects/examples/boost-openmethods/templated.cpp:57:26: error: expected unqualified-id
   57 | static value<T>::override<plus_value<T>> override_plus_value;
      |                          ^
/Users/jagot/work/projects/examples/boost-openmethods/templated.cpp:65:26: error: expected unqualified-id
   65 | static value<T>::override<times_value<T>> override_times_value;
      |                          ^
3 errors generated.

What I am doing wrong? Is it possible to accomplish the same less verbosely, i.e. using the macros, and such that value is a callable function, so I don't have to call using value<T>::fn?

Side note

My code is already written using lots of shared_ptrs. Is it possible to somehow call an open method using shared pointers directly, without the intermediate conversion to shared_virtual_ptr?

In the documentation found here, make_unique_virtual is written as make_unique_virtual_ptr, and similarly for make_shared_virtual. Luckily, my compiler told me to use the correct method.

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions