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

Labels

No labels
No labels

Type

No type
No fields configured for issues without a type.

Projects

No projects

Milestone

No milestone

Relationships

None yet

Development

No branches or pull requests

Issue actions