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:
- a
Tablespecialization instance returned byFactory - a
Schemespecialization that is complient with theTablespecialization 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).
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?
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.
Then you only mention the factory method once per use.
See it on godbolt