Skip to content

Cannot register node that takes interface as extra parameter #945

Closed
@gvallicrosa

Description

@gvallicrosa

Describe the bug

Using release 4.6.2.

I was trying to register a node that depends on an interface in its constructor:

#include <behaviortree_cpp/bt_factory.h>

// interface
struct IMotor {
  virtual void doMove() = 0;
};

// implementation
struct LinearMotor : public IMotor {
  void doMove() override {}
};

// node using interface
class PathFollow : public BT::StatefulActionNode {
 public:
  PathFollow(const std::string& name, const BT::NodeConfig& config, IMotor& motor)
      : BT::StatefulActionNode(name, config), imotor_(motor) {}
  static BT::PortsList providedPorts() { return {}; }
  BT::NodeStatus onStart() override { return BT::NodeStatus::SUCCESS; }
  BT::NodeStatus onRunning() override { return BT::NodeStatus::SUCCESS; }
  void onHalted() override {}

 private:
  IMotor& imotor_;
};

int main() {
  LinearMotor motor;
  BT::BehaviorTreeFactory factory;
  factory.registerNodeType<PathFollow>("PathFollow", motor);
  factory.registerNodeType<PathFollow>("PathFollow", PathFollow::providedPorts(), motor);
  factory.registerNodeType<PathFollow, LinearMotor&>("PathFollow", PathFollow::providedPorts(), motor);
  factory.registerNodeType<PathFollow, IMotor&>("PathFollow", PathFollow::providedPorts(), motor);
}

Trying different ways to register the node, none of them compile. Is there a way to use an interface as an extra argument? Already checked the tutorial 8 and normal examples with values compile without problems.

Here is the compilation output:

In file included from /interface.cc:1:
/usr/local/include/behaviortree_cpp/bt_factory.h: In instantiation of ‘void BT::BehaviorTreeFactory::registerNodeType(const string&, ExtraArgs ...) [with T = PathFollow; ExtraArgs = {LinearMotor}; std::string = std::__cxx11::basic_string<char>]’:
/interface.cc:30:39:   required from here
/usr/local/include/behaviortree_cpp/bt_factory.h:379:21: error: static assertion failed: [registerNode]: since you have a static method providedPorts(),
you MUST add a constructor with signature:
(const std::string&, const NodeConfig&)

  379 |       static_assert(!(has_static_ports_list && !param_constructable),
      |                     ^~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
/usr/local/include/behaviortree_cpp/bt_factory.h:379:21: note: ‘((!(bool)has_static_ports_list) || ((bool)param_constructable))’ evaluates to false
/usr/local/include/behaviortree_cpp/bt_factory.h: In instantiation of ‘void BT::BehaviorTreeFactory::registerNodeType(const string&, const PortsList&, ExtraArgs ...) [with T = PathFollow; ExtraArgs = {LinearMotor}; std::string = std::__cxx11::basic_string<char>; BT::PortsList = std::unordered_map<std::__cxx11::basic_string<char>, BT::PortInfo>]’:
/interface.cc:31:39:   required from here
/usr/local/include/behaviortree_cpp/bt_factory.h:343:41: error: static assertion failed: [registerNode]: the registered class must have at least one of these two constructors:
  (const std::string&, const NodeConfig&) or (const std::string&)
Check also if the constructor is public!)
  343 |     static_assert(default_constructable || param_constructable,
      |                   ~~~~~~~~~~~~~~~~~~~~~~^~~~~~~~~~~~~~~~~~~~~~
/usr/local/include/behaviortree_cpp/bt_factory.h:343:41: note: ‘(((bool)default_constructable) || ((bool)param_constructable))’ evaluates to false
/usr/local/include/behaviortree_cpp/bt_factory.h: In instantiation of ‘void BT::BehaviorTreeFactory::registerNodeType(const string&, const PortsList&, ExtraArgs ...) [with T = PathFollow; ExtraArgs = {IMotor&}; std::string = std::__cxx11::basic_string<char>; BT::PortsList = std::unordered_map<std::__cxx11::basic_string<char>, BT::PortInfo>]’:
/interface.cc:33:48:   required from here
/usr/local/include/behaviortree_cpp/bt_factory.h:349:67: error: cannot allocate an object of abstract type ‘IMotor’
  349 |     registerBuilder(CreateManifest<T>(ID, ports), CreateBuilder<T>(args...));
      |                                                   ~~~~~~~~~~~~~~~~^~~~~~~~~
/interface.cc:4:8: note:   because the following virtual functions are pure within ‘IMotor’:
    4 | struct IMotor {
      |        ^~~~~~
/interface.cc:5:16: note:     ‘virtual void IMotor::doMove()’
    5 |   virtual void doMove() = 0;
      |

This node should be "param_constructable" with the LinearMotor struct passed to it. Any guess on how to do it? Am I missing something basic?

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