Tenho muitas classes polimórficas. Cada uma delas tem uma classe aninhada chamada Configuration
contendo todos os hiperparâmetros requeridos pela classe. Para cada árvore de classes, crio uma variante das configurações possíveis e uma função instantiate
capaz de criar a instância a partir da configuração. Como no exemplo abaixo.
# include <variant>
# include <memory>
class Base
{};
class A : public Base
{
public:
struct Configuration { /*hyperparameters*/ };
A(Configuration const&) {}
};
class B : public Base
{
public:
struct Configuration { /*hyperparameters*/ };
B(Configuration const&) {}
};
struct BaseConfiguration
{
using type = std::variant<A::Configuration, B::Configuration>;
static std::unique_ptr<Base> instantiate(type const& config);
};
struct BaseVisitor
{
// My problem is here...
std::unique_ptr<Base> operator()(A::Configuration const& config)
{ return std::make_unique<A>(config); }
std::unique_ptr<Base> operator()(B::Configuration const& config)
{ return std::make_unique<B>(config); }
};
std::unique_ptr<Base> BaseConfiguration::instantiate(type const& config)
{
return std::visit(BaseVisitor(), config);
}
int main()
{
BaseConfiguration::type config = A::Configuration();
std::unique_ptr<Base> x = BaseConfiguration::instantiate(config);
return 0;
}
Gostaria de evitar o código redundante na BaseVisitor
classe. Todas as funções são exatamente as mesmas (muitas funções para algumas hierarquias). Existe uma maneira de reduzir esse código? Tentei com a seguinte abordagem de modelo, mas não compila (com C++17).
struct BaseVisitor
{
template <typename X>
std::unique_ptr<Base> operator()(typename X::Configuration const& config)
{ return std::make_unique<X>(config); }
};
Erro do compilador:
<source>: In static member function 'static std::unique_ptr<Base> BaseConfiguration::instantiate(const type&)':
<source>:36:22: error: no matching function for call to 'visit(BaseVisitor, const BaseConfiguration::type&)'
36 | return std::visit(BaseVisitor(), config);
| ~~~~~~~~~~^~~~~~~~~~~~~~~~~~~~~~~