Skip to content

Fix OpenSim's property macros are namespace-dependent #3468

@adamkewley

Description

@adamkewley

If I write a custom component class that lies outside of the OpenSim namespace:

namespace
{
  class FrameDefinitionMesh final : public OpenSim::Component {
      OpenSim_DECLARE_CONCRETE_OBJECT(FrameDefinitionMesh, OpenSim::Component);
  public:
      OpenSim_DECLARE_PROPERTY(scale_factors, SimTK::Vec3, "scale factors in X, Y, and Z directions of the mesh");
  };
}

Then it will fail to compile unless the anonymous namespace is named OpenSim, or a using namespace OpenSim; declaration is placed above the class declaration. Example compiler errors:

FrameDefinitionTab.cpp(58): error C3646: 'PropertyIndex_scale_factors': unknown override specifier
FrameDefinitionTab.cpp(58): error C4430: missing type specifier - int assumed. Note: C++ does not support default-int
FrameDefinitionTab.cpp(58): error C2143: syntax error: missing ';' before '<'
FrameDefinitionTab.cpp(58): error C2334: unexpected token(s) preceding '{'; skipping apparent function body
FrameDefinitionTab.cpp(58): error C2327: '`anonymous-namespace'::FrameDefinitionMesh::Property': is not a type name, static, or enumerator
FrameDefinitionTab.cpp(56): error C2280: '`anonymous-namespace'::FrameDefinitionMesh &`anonymous-namespace'::FrameDefinitionMesh::operator =(const `anonymous-namespace'::FrameDefinitionMesh &)': attempting to reference a deleted function
  FrameDefinitionTab.cpp(59): note: compiler has generated '`anonymous-namespace'::FrameDefinitionMesh::operator =' here
  FrameDefinitionTab.cpp(59): note: '`anonymous-namespace'::FrameDefinitionMesh &`anonymous-namespace'::FrameDefinitionMesh::operator =(const `anonymous-namespace'::FrameDefinitionMesh &)': function was implicitly deleted because '`anonymous-namespace'::FrameDefinitionMesh' has a data member '`anonymous-namespace'::FrameDefinitionMesh::Property' of const-qualified non-class type
  FrameDefinitionTab.cpp(58): note: see declaration of '`anonymous-namespace'::FrameDefinitionMesh::Property'
FrameDefinitionTab.cpp(58): error C2065: 'PropertyIndex_scale_factors': undeclared identifier
FrameDefinitionTab.cpp(58): error C2039: 'PropertyIndex_scale_factors': is not a member of '`anonymous-namespace'::FrameDefinitionMesh'
  FrameDefinitionTab.cpp(55): note: see declaration of '`anonymous-namespace'::FrameDefinitionMesh'
FrameDefinitionTab.cpp(58): error C2039: 'updProperty_scale_factors': is not a member of '`anonymous-namespace'::FrameDefinitionMesh'
  FrameDefinitionTab.cpp(55): note: see declaration of '`anonymous-namespace'::FrameDefinitionMesh'
FrameDefinitionTab.cpp(58): error C2039: 'getProperty_scale_factors': is not a member of '`anonymous-namespace'::FrameDefinitionMesh'
  FrameDefinitionTab.cpp(55): note: see declaration of '`anonymous-namespace'::FrameDefinitionMesh'

The reason this happens is because the macros are written with the assumption that they will be expanded inside those namespaces (or, with those namespaces brought into the global namespace via a using namespace declaration).

E.g. the OpenSim_DECLARE_PROPERTY_HELPER_PROPERTY_MEMBERS macro in Property.h uses an OpenSim::PropertyIndex without the namespace qualifier, so the compiler will fail to find PropertyIndex unless the expansion point is defined within OpenSim or is inside a block that has a using namespace declaration:

// OpenSim/Common/Property.h:1255

// Used by OpenSim_DECLARE_PROPERTY_HELPER below to control the members
// that are used with SWIG.
#ifndef SWIG
#define OpenSim_DECLARE_PROPERTY_HELPER_PROPERTY_MEMBERS(name, T)           \
    /** @cond **/                                                           \
    PropertyIndex PropertyIndex_##name;                                     \
    const Property<T>& getProperty_##name() const                           \
    {   return this->template getProperty<T>(PropertyIndex_##name); }       \
    Property<T>& updProperty_##name()                                       \
    {   return this->template updProperty<T>(PropertyIndex_##name); }       \
    /** @endcond **/
#else
// No need to wrap internal PropertyIndex or auto-generated methods that return
// templatized Properties
#define OpenSim_DECLARE_PROPERTY_HELPER_PROPERTY_MEMBERS(name, T)
#endif

OpenSim Creator entirely bans using namespace, purely as a defensive measure, but this means that I either have to drop the rule when using OpenSim (undesirable), or define all of my downstream components within the OpenSim namespace (also undesirable).

Metadata

Metadata

Assignees

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