Google Groups no longer supports new Usenet posts or subscriptions. Historical content remains viewable.
Dismiss

How to return a template?

55 views
Skip to first unread message

Heinz-Mario Frühbeis

unread,
Apr 15, 2016, 3:17:43 AM4/15/16
to
Hi,

I want to use a template function to return a new (new-)instance of a class.

template < typename t_New >
t_New* Register_New(std::string vName, int vType){
c_idasection *nSec = NULL;
c_IDALabel *nLbl = NULL;
if(vType == 1){
nSec = new c_idasection(this, vName, 1);
return nSec;
} else if (vType == 3) {
nLbl = new c_IDALabel(this, vName, 1);
return nLbl;
}
return NULL;
}

c_IDALabel *lblInf = mXIDA.Register_New("lblInf", 3);

But I get the error:
/media/.../ida_login/c_xida.h:58: note: template argument
deduction/substitution failed:

I also tried:
template < typename t_New >
int Register_New(t_New *vNew, std::string vName, int vType){
c_idasection *nSec = NULL;
c_IDALabel *nLbl = NULL;
tdPair_RegObjA nPairA;
tdPair_RegObj nPair;
for(int i = 0; i < (int) this->mVecReg.size(); i++){
if(this->mVecReg[i].first == vName){
return 0;
}
}
if(vType == 1){
nSec = new c_idasection(this, vName, 1);
vNew = nSec;
} else if (vType == 3) {
nLbl = new c_IDALabel(this, vName, 1);
vNew = nLbl;
}
nPairA.first = vType;
nPairA.second = (void*) vNew;
nPair.first = vName;
nPair.second = nPairA;
this->mVecReg.push_back(nPair);
cout << "XIDA REGISTER OK >> TYPE == " << vType << " " << vName <<
endl ; cout.flush();
return 1;
}

But than I get the error:
'cannot convert from c_idasection to c_IDALAbel'

How can I make it work?

TIA
Heinz-Mario Frühbeis

Paavo Helde

unread,
Apr 15, 2016, 4:28:53 AM4/15/16
to
It looks like you want to decide at run-time which class to create, i.e.
you want you decide at run-time which code to run. Alas, templates are a
compile-time feature, so it is impossible to use them in such a way
(with templates you need to know already at compile time which code you
want to run).

Not exactly sure what you want to achieve. One approach would be to
derive c_idasection and c_IDALabel from a common base class with virtual
interface. The function which does the runtime dispatch is an ordinary
function, not a template:

base* Register_New(std::string vName, int vType){
if(vType == 1) {
return new c_idasection(this, vName, 1);
} else if (vType == 3) {
return new c_IDALabel(this, vName, 1);
}
return NULL;
}

base* obj = Register_New("blabla", 1);
obj->SomeVirtualFunction();

Of course, using raw pointers is error prone, suggesting to use some
sort of smartpointers like std::unique_ptr or std::shared_ptr instead.

Another possibility is that you want to process things by some common
template function. In this case you still need non-template dispatch
function, which forwards to templates:

template<class T>
void Process(std::string vName) {
T obj(this, vName, 1);
obj.DoSomething();
// call some other templates, etc.
}

void Dispatch(std::string vName, int vType){
if(vType == 1) {
Process<c_idasection>(vName);
} else if (vType == 3) {
Process<c_IDALabel>(vName);
}
}

In this approach, there is no common base class or virtual functions
needed, but for example keeping the objects around for a later use would
be more cumbersome.

HTH
Paavo

Heinz-Mario Frühbeis

unread,
Apr 15, 2016, 5:26:14 AM4/15/16
to
Am 15.04.2016 um 10:28 schrieb Paavo Helde:
> On 15.04.2016 10:17, Heinz-Mario Frühbeis wrote:
>> Hi,
[...]
Oh yes! You brought me on the right way!

My solution:

template < class T >
T* GetClass(std::string vName){
return new T(this, vName, 1);
}

template < typename t_New >
t_New* Register_New(std::string vName, int vType){
tdPair_RegObjA nPairA;
tdPair_RegObj nPair;
t_New *n_New = NULL;
for(int i = 0; i < (int) this->mVecReg.size(); i++){
if(this->mVecReg[i].first == vName){
return NULL;
}
}
n_New = GetClass <t_New> (vName);
nPairA.first = vType;
nPairA.second = (void*) n_New;
nPair.first = vName;
nPair.second = nPairA;
this->mVecReg.push_back(nPair);
cout << "XIDA REGISTER OK >> TYPE == " << vType << " " << vName <<
endl ; cout.flush();
return n_New;
}

c_IDAButton *lblInf = mXIDA.Register_New <c_IDAButton> ("lblInf", 3);

Thanks, sir; thanks a lot!

Regards
Heinz-Mario Frühbeis

Alf P. Steinbach

unread,
Apr 15, 2016, 11:31:15 AM4/15/16
to
On 15.04.2016 11:26, Heinz-Mario Frühbeis wrote:
>
> Oh yes! You brought me on the right way!
>
> My solution:
>
> template < class T >
> T* GetClass(std::string vName){
> return new T(this, vName, 1);
> }
>
> template < typename t_New >
> t_New* Register_New(std::string vName, int vType){
> tdPair_RegObjA nPairA;
> tdPair_RegObj nPair;
> t_New *n_New = NULL;
> for(int i = 0; i < (int) this->mVecReg.size(); i++){
> if(this->mVecReg[i].first == vName){
> return NULL;
> }
> }
> n_New = GetClass <t_New> (vName);
> nPairA.first = vType;
> nPairA.second = (void*) n_New;
> nPair.first = vName;
> nPair.second = nPairA;
> this->mVecReg.push_back(nPair);
> cout << "XIDA REGISTER OK >> TYPE == " << vType << " " << vName
> << endl ; cout.flush();
> return n_New;
> }
>
> c_IDAButton *lblInf = mXIDA.Register_New <c_IDAButton> ("lblInf", 3);

This does not make sense to me.

The code above ensures that for a given type t_New only the first call
of `Register_New` with a given name will return a pointer to object,
where a type-erased (unusable) pointer to that object is saved in a
vector, and that all subsequent calls with that name should return NULL.

What's the POINT of this?

Anyway, regarding the use of Hungarian notation (the silly prefixes),
that was invented in order to support the help system in Microsoft's
"Programmers' Workbench" IDE in the middle to late 1980's, IIRC.

It's at least 26 years obsolete.

Although the [1] Wikipedia article on Hungarian notation sports some
statements (especially about BCPL) that look like uninformed guesses,
check out its opinion section.


Cheers,

- Alf

Notes:
[1] https://en.wikipedia.org/wiki/Hungarian_notation#Notable_opinions

Ian Collins

unread,
Apr 15, 2016, 4:17:51 PM4/15/16
to
On 04/15/16 19:17, Heinz-Mario Frühbeis wrote:
> Hi,
>
> I want to use a template function to return a new (new-)instance of a class.
>
> template < typename t_New >
> t_New* Register_New(std::string vName, int vType){
> c_idasection *nSec = NULL;

What the point of all those t_ v and c_ prefixes? They're just annoying
noise that gets in the way of reading the code.

--
Ian Collins

Richard

unread,
Apr 15, 2016, 5:06:31 PM4/15/16
to
[Please do not mail me a copy of your followup]

Paavo Helde <myfir...@osa.pri.ee> spake the secret code
<jradnZCXm9GkO43K...@giganews.com> thusly:

>It looks like you want to decide at run-time which class to create, i.e.
>you want you decide at run-time which code to run. Alas, templates are a
>compile-time feature, so it is impossible to use them in such a way
>(with templates you need to know already at compile time which code you
>want to run).

Here's how I think of it:

Templates are static (compile-time) polymorphism.

Virtual methods and abstract base classes are dynamic (run-time)
polymorphism.
--
"The Direct3D Graphics Pipeline" free book <http://tinyurl.com/d3d-pipeline>
The Computer Graphics Museum <http://computergraphicsmuseum.org>
The Terminals Wiki <http://terminals.classiccmp.org>
Legalize Adulthood! (my blog) <http://legalizeadulthood.wordpress.com>
0 new messages