Follow

Keep Up to Date with the Most Important News

By pressing the Subscribe button, you confirm that you have read and are agreeing to our Privacy Policy and Terms of Use
Contact

How to not having to specify the return type of a factory

I want consumers to use a Factory for the construction of special derivations of a Scheme.

Mandatorily, when asking a method from the factory, it returns a Table specialization. A method implementation comprises of two things:

  1. a Table specialization instance returned by Factory
  2. a Scheme specialization that is complient with the Table specialization type.

The point of this whole question is convenience, in that I do not want to force consumers at knowing what scheme is compliant to which table, not even to mention what table type a given factory method returns. And lastly, I still want advanced users to still be able to force-specify the Scheme specialization to be used (that’s why factory only returns a table and not a full method; in that vain, I do not want to employ arguments in any factory routines).

MEDevel.com: Open-source for Healthcare and Education

Collecting and validating open-source software for healthcare, education, enterprise, development, medical imaging, medical records, and digital pathology.

Visit Medevel

Because I cannot use dynamic memory, I employ a template Scheme_handle class that can hold an instance of a Scheme specialization. But this defies its own purpose when the consumer is still demanded to know the necessary template type.

Below is my attempt.

#include<iostream>
//#include<memory> // infeasible since dynamic allocation

struct Table{ double data; };
struct Scheme{};
//
struct Table_A: Table{};
struct Table_B: Table{}; // there are too many different scheme types for use of std::conditional_t
//
struct Scheme_A: Scheme{
    Scheme_A(Table_A const& t){}
};
struct Scheme_B: Scheme{
    Scheme_B(Table_A const& t){}
    Scheme_B(Table_B const& t){}
};

struct Factory{
    /* factory implementation ... */
    static Table_A make_x(){ return Table_A{}; } // it is mandatory that Factory returns Tables
    static Table_B make_y(){ return Table_B{}; } // otherwise, Table would not have been
    static Table_A make_z(){ return Table_A{}; } // included in this minimum code example
};

// specializations still need a declaration in 2023
template<typename TableType> class Scheme_handle;

// the following two lines of terrible boilerplate are necessary 
// because c++ wont allow template<> using Scheme_handle<Table_A> = Scheme_A;
// same goes for typedef
template<> class Scheme_handle<Table_A>: public Scheme_A{ public: Scheme_handle(Table_A const& t):Scheme_A(t){} }; // Table_A -> Scheme_A
template<> class Scheme_handle<Table_B>: public Scheme_B{ public: Scheme_handle(Table_B const& t):Scheme_B(t){} }; // Table_B -> Scheme_B


// here is the consumer code that I need to be handable
struct MyClass{
    //
    // what more needs the compiler so one can drop the "<Table_A>" ?
    Scheme_handle<Table_A>   x1 = Factory::make_x(); // at least this gives me a handle to a scheme
    //
    Scheme_handle<Table_B>   y1 = Factory::make_y(); // the consumer does not possibly want to remember the scheme type of y.
    Scheme_handle<Table_B>   y2 = Factory::make_y(); // schemes arent singletons!
    //
    Scheme_B                 x2 = Factory::make_x(); // a table does not imply a scheme!
    // (but for each table there is a default compliant scheme, as defined by the mapping Scheme_handle : TableType -> SchemeType )
};

int main(){
    MyClass q;
}

I assume what I want to do is pretty standard. How is it supposed to be done?, i.e. how can the handle (without dynamic memory) be implemented?

>Solution :

A data-member of a class has to have a concrete type. There is no mechanism to deduce it from an initialiser. What you can do is move the desired factory method into the type.

template<auto FactoryMethod> class Scheme_for;

template<typename TableType, TableType(*FactoryMethod)()> 
class Scheme_for<FactoryMethod> : public Scheme_handle<TableType>{ 
    public: Scheme_for(): Scheme_handle<TableType>(FactoryMethod()){} 
};

Then you only mention the factory method once per use.

struct MyClass{
    Scheme_for<Factory::make_x> x1;
    Scheme_for<Factory::make_y> y1;
    Scheme_for<Factory::make_y> y2;
    Scheme_B  x2 = Factory::make_x();
};

See it on godbolt

Add a comment

Leave a Reply

Keep Up to Date with the Most Important News

By pressing the Subscribe button, you confirm that you have read and are agreeing to our Privacy Policy and Terms of Use

Discover more from Dev solutions

Subscribe now to keep reading and get access to the full archive.

Continue reading