Defined in <plugin/PluginRegister.hh>.
#define REGISTER_WITH_CONFIG( CLASS, BASE, CONFIG )
#define REGISTERBYNAME_WITH_CONFIG( NAME, CLASS, BASE, CONFIG )
Register CLASS with both a default factory and a config factory, so both create overloads work:
BASE::create( key ) // -> new CLASS()
BASE::create( key, cfg ) // -> new CLASS( std::any_cast<CONFIG const&>( any(cfg) ) )
REGISTER_WITH_CONFIG(C, B, Cfg) uses key "C"; REGISTERBYNAME_WITH_CONFIG("n", C, B, Cfg) uses key "n".
Requirements
CLASSderives fromBASE.CLASShas an accessibleCLASS()andCLASS( CONFIG const& ).CONFIGis copyable (it is stored instd::any).
The type check
The config factory is:
static Base* CreateFromConfig( std::any const& cfg )
{
return new T( std::any_cast< Config const& >( cfg ) );
}
The host's create(key, x) builds std::any( x ) from x's concrete type. std::any_cast<Config const&> succeeds only if that concrete type is exactly Config — otherwise std::bad_any_cast. There is no conversion, inheritance slicing, or narrowing: create("Circle", 42) (an int) does not match Circle::Config.
Example
// Circle.cpp → libCircle.so
class Circle : public Shape
{
public:
struct Config { unsigned int r = 0; };
Circle() : radius( 0 ) {}
explicit Circle( Config const& c ) : radius( c.r ) {}
// ... overrides ...
private:
unsigned int radius;
};
REGISTER_WITH_CONFIG( Circle, Shape, Circle::Config );
Host:
auto a = Shape::create( "Circle" ); // radius 0
auto b = Shape::create( "Circle", Circle::Config{ 42 } ); // radius 42
auto c = Shape::create( "Circle", 42 ); // throws std::bad_any_cast
Notes
- Convention in the shipped example: the
Configstruct is a nested type (Circle::Config) declared in the plugin's public header so the host can name it. - A plugin registered this way still answers
create(key)with the default ctor — you do not lose the parameterless path. - Using
create(key)semantics on a plainREGISTERplugin then passing a config throwsstd::runtime_error— see Creator.

