I know the reason for the problem. Template instanziation happens at compile
time.
So it cannot handle function parameter of createInstance function at
runtime.
The question is: how shall I realize it differently as follows [pseudo
code]:
if(i == 1)
return C<1>();
if(i == 2)
return C<2>();
// ... maintenance nightmare ...
#include <iostream>
class Base {
public:
virtual void foo() = 0;
};
template<int T>
class C : public Base {
public:
virtual void foo() { /* default does nothing */ }
};
template<>
class C<1> : public Base {
public:
virtual void foo() { std::cout << "C<1>::foo "; }
};
template<>
class C<2> : public Base {
public:
virtual void foo() { std::cout << "C<2>::foo "; }
};
class Factory {
public:
static Base& createInstance(int i);
};
Base& Factory::createInstance(int i) {
// PROBLEM:
// error C2971: 'C' : template parameter 'T' : 'i' : a local variable
cannot be used as
// a non-type argument
// WORKS: int const val = 0;
return C<i>(); //ignore warning: returning address of local variable or
temporary
}
void main() {
Base& anInstance = Factory::createInstance(1);
Base& anotherInstance = Factory::createInstance(2);
}
--
[ See http://www.gotw.ca/resources/clcm.htm for info about ]
[ comp.lang.c++.moderated. First time posters: Do this! ]
|
|
0
|
|
|
|
Reply
|
vl106
|
2/5/2009 2:34:09 AM |
|
On 5 фев, 11:34, "vl106" <vl...@hotmail.com> wrote:
> Base& Factory::createInstance(int i) {
> // PROBLEM:
> // error C2971: 'C' : template parameter 'T' : 'i' : a local variable
> cannot be used as
> // a non-type argument
> // WORKS: int const val = 0;
> return C<i>(); //ignore warning: returning address of local variable or
> temporary
>
> }
Option 1, "switch" statement is much faster than "if" one:
Base& Factory::createInstance(int i) {
switch(i){
case 1: return C<1>();
case 2: return C<2>();
...
}
}
Option 2, linear recursive helper function:
const int max_n = 100;
template<int n>
struct helper
{
static Base& func(int i)
{
return i == n? C<n>() : helper<n+1>::func(i);
}
};
template<>
struct helper<max_n>
{
static Base& func(int i)
{
return C<max_n>();
}
};
Base& Factory::createInstance(int i) {
return helper<0>(i);
}
Option 3, similar to Option 1 but using Boost.Preprocessor library you
can avoid manual array completion and functions writing:
// the following functions can be generated by Boost.Preprocessor
(http://www.boost.org/doc/libs/1_37_0/libs/preprocessor/doc/
index.html), takes 10 minutes to learn, 5 minutes to write generator
for hungred functions.
Base& func0()
{
return C<0>();
}
Base& func1()
{
return C<1>();
}
Base& func2()
{
return C<2>();
}
....
Base& Factory::createInstance(int i) {
const Base& (*ptrs)()[]={func0,func1,func2,... /* can be filled by
Boost.Preprocessor too */};
return ptrs[i]();
}
--
[ See http://www.gotw.ca/resources/clcm.htm for info about ]
[ comp.lang.c++.moderated. First time posters: Do this! ]
|
|
0
|
|
|
|
Reply
|
potapov
|
2/5/2009 8:05:27 AM
|
|
"vl106" <vl106@hotmail.com> writes:
> The question is: how shall I realize it differently as follows [pseudo
> code]:
> if(i == 1)
> return C<1>();
> if(i == 2)
> return C<2>();
> // ... maintenance nightmare ...
vs
> Base& Factory::createInstance(int i) {
> // PROBLEM:
> // error C2971: 'C' : template parameter 'T' : 'i' : a local variable
> cannot be used as
> // a non-type argument
> // WORKS: int const val = 0;
> return C<i>(); //ignore warning: returning address of local variable or
> temporary
That's a rather serious warning you're ignoring.
> }
>
> void main() {
> Base& anInstance = Factory::createInstance(1);
> Base& anotherInstance = Factory::createInstance(2);
> }
What is it you are actually trying to do? How do C<1> and C<2> differ?
Do all the C<some-int-value> specializations actually exist and make
sense, or only those you've explicitly specialized?
Without further information, if the list is limited, I'd go with the
switch. You could probably remove the duplication with some preprocessor
magic such as that in the Boost Preprocessor library.
Anthony
--
Author of C++ Concurrency in Action | http://www.manning.com/williams
just::thread C++0x thread library | http://www.stdthread.co.uk
Just Software Solutions Ltd | http://www.justsoftwaresolutions.co.uk
15 Carrallack Mews, St Just, Cornwall, TR19 7UL, UK. Company No. 5478976
[ See http://www.gotw.ca/resources/clcm.htm for info about ]
[ comp.lang.c++.moderated. First time posters: Do this! ]
|
|
0
|
|
|
|
Reply
|
Anthony
|
2/5/2009 8:05:36 AM
|
|
On 5 Feb., 09:34, "vl106" <vl...@hotmail.com> wrote:
> I know the reason for the problem. Template instanziation happens at compile
> time.
> So it cannot handle function parameter of createInstance function at
> runtime.
>
> The question is: how shall I realize it differently as follows [pseudo
> code]:
> if(i == 1)
> return C<1>();
> if(i == 2)
> return C<2>();
> // ... maintenance nightmare ...
I'd say it depends on what you are trying to achieve.
> #include <iostream>
> class Base {
> public:
> virtual void foo() = 0;
>
> };
>
> template<int T>
> class C : public Base {
> public:
> virtual void foo() { /* default does nothing */ }
>
> };
>
> template<>
> class C<1> : public Base {
> public:
> virtual void foo() { std::cout << "C<1>::foo "; }
>
> };
>
> template<>
> class C<2> : public Base {
> public:
> virtual void foo() { std::cout << "C<2>::foo "; }
>
> };
>
> class Factory {
> public:
> static Base& createInstance(int i);
>
> };
why a static class member function?
> Base& Factory::createInstance(int i) {
> // PROBLEM:
> // error C2971: 'C' : template parameter 'T' : 'i' : a local variable
> cannot be used as
> // a non-type argument
> // WORKS: int const val = 0;
> return C<i>(); //ignore warning: returning address of local variable or
> temporary
> }
Your factory approach is flawed. You're returning a reference to a
local variable which becomes a dangling reference.
> void main() {
> Base& anInstance = Factory::createInstance(1);
> Base& anotherInstance = Factory::createInstance(2);
>
> }
The function 'main' needs to return an int.
Here the arguments to createInstance are constant expressions. So,
technically you could convert createInstance to a function template.
template<int I>
C<I> createInstance() { return C<I>(); }
int main() {
const Base& b = createInstance<2>();
b.some_virtual_const_function();
}
But what would be the point of it? It looks like you want runtime
polymorphism. Why don't you simply make the int a parameter to the
constructor?
// lib.hh
#include <memory>
class Base {
public:
virtual void foo() = 0;
virtual ~Base() {}
};
std::auto_ptr<Base> factory(int);
// lib.cc
#include <iostream>
#include <ostream>
#include <memory>
class C : public Base {
int myint;
public:
explicit C (int i) : myint(i) {}
~C() {}
void foo();
};
void C::foo() {
std::cout << "C::foo says " << myint << std::endl;
}
std::auto_ptr<Base> factory(int i) {
std::auto_ptr<Base> ap (new C(i));
return ap;
}
// main.cc
#include <memory>
int main() {
std::auto_ptr<Base> apb = factory(2);
apb->foo();
}
Be sure to check out related C++ idioms: handle/body, counted body,
envelope/letter, ...
Cheers!
SG
--
[ See http://www.gotw.ca/resources/clcm.htm for info about ]
[ comp.lang.c++.moderated. First time posters: Do this! ]
|
|
0
|
|
|
|
Reply
|
SG
|
2/5/2009 8:05:44 AM
|
|
I have to better describe the problem:
[kind of pseudo code]
void receive_message(int messageId, char* data) {
Base& new_message = Factory::createMessage(messageId, data); //
transition to C++
new_message.process();
}
>From old, non-C++ library I receive messages identified by int id.
I want to map this "event" into an "object-oriented" message. Further
receive_message should stay stable. That is when a new kind of message
is received I only want to create a new specialization
(C<new_message_id>).
This specialization will have a process method with different
behaviour.
--
[ See http://www.gotw.ca/resources/clcm.htm for info about ]
[ comp.lang.c++.moderated. First time posters: Do this! ]
|
|
0
|
|
|
|
Reply
|
vl106
|
2/6/2009 7:38:43 AM
|
|
vl106 <vl106@hotmail.com> writes:
> I have to better describe the problem:
>
> [kind of pseudo code]
> void receive_message(int messageId, char* data) {
> Base& new_message = Factory::createMessage(messageId, data); //
> transition to C++
> new_message.process();
> }
>
>>From old, non-C++ library I receive messages identified by int id.
> I want to map this "event" into an "object-oriented" message. Further
> receive_message should stay stable. That is when a new kind of message
> is received I only want to create a new specialization
> (C<new_message_id>).
> This specialization will have a process method with different
> behaviour.
Why do you need a specialization? Why can't you just define a normal
class derived from Base? Once you're out of createMessage you can't
access the derived class anyway unless you know what it is.
I would just have createMessage do a lookup of ID to class to create,
either using a switch statement or a lookup table.
Anthony
--
Author of C++ Concurrency in Action | http://www.manning.com/williams
just::thread C++0x thread library | http://www.stdthread.co.uk
Just Software Solutions Ltd | http://www.justsoftwaresolutions.co.uk
15 Carrallack Mews, St Just, Cornwall, TR19 7UL, UK. Company No. 5478976
[ See http://www.gotw.ca/resources/clcm.htm for info about ]
[ comp.lang.c++.moderated. First time posters: Do this! ]
|
|
0
|
|
|
|
Reply
|
Anthony
|
2/6/2009 12:33:18 PM
|
|
On 6 Feb., 14:38, vl106 <vl...@hotmail.com> wrote:
> I want to map this "event" into an "object-oriented" message. Further
> receive_message should stay stable. That is when a new kind of message
> is received I only want to create a new specialization
> (C<new_message_id>).
> This specialization will have a process method with different
> behaviour.
You can't instantiate a class template with runtime parameters.
Templates won't help you here. There's no way around checking the ID
at runtime -- via
1. if/else if/else or
2. switch/case or
3. a map that maps message ID to a specific message factory.
I recently had a similar case and went with the 3rd approach. It only
requires the factories to register themselves at program start up
(plug-in like). So, after writing your new message class and its
factory you only have to add this factory to the map.
Cheers!
SG
--
[ See http://www.gotw.ca/resources/clcm.htm for info about ]
[ comp.lang.c++.moderated. First time posters: Do this! ]
|
|
0
|
|
|
|
Reply
|
SG
|
2/6/2009 12:34:36 PM
|
|
potapov.d@gmail.com wrote:
>
> Option 1, "switch" statement is much faster than "if" one:
Are you sure? I'd say, the "switch" statement *may* be faster,
but it all depends on the details of the implementation;
for example, the "switch" statement may be implemented
as a series of the "if"..."else"... statements.
--
Seungbeom Kim
[ See http://www.gotw.ca/resources/clcm.htm for info about ]
[ comp.lang.c++.moderated. First time posters: Do this! ]
|
|
0
|
|
|
|
Reply
|
Seungbeom
|
2/7/2009 11:45:11 AM
|
|
On 7 ���, 20:45, Seungbeom Kim <musip...@bawi.org> wrote:
> Are you sure? I'd say, the "switch" statement *may* be faster,
> but it all depends on the details of the implementation;
> for example, the "switch" statement may be implemented
> as a series of the "if"..."else"... statements.
We're speaking about compilers here, not the hand-made trash, right?
So, concerning compilers, would you be so kind to provide the link to
one, that use the series of "if ... else ..." instead of "switch"? I
can confirm that VC++6.0 (or later) and GCC 4.1 (or later) doesn't.
--
[ See http://www.gotw.ca/resources/clcm.htm for info about ]
[ comp.lang.c++.moderated. First time posters: Do this! ]
|
|
0
|
|
|
|
Reply
|
potapov
|
2/8/2009 4:22:35 PM
|
|
<potapov.d@gmail.com>
>> Are you sure? I'd say, the "switch" statement *may* be faster,
>> but it all depends on the details of the implementation;
>> for example, the "switch" statement may be implemented
>> as a series of the "if"..."else"... statements.
>
> We're speaking about compilers here, not the hand-made trash, right?
> So, concerning compilers, would you be so kind to provide the link to
> one, that use the series of "if ... else ..." instead of "switch"? I
> can confirm that VC++6.0 (or later) and GCC 4.1 (or later) doesn't.
The compilers did a great job optimizing switch using many forms --
including chained if, table fragments, full table -- chosing by the actual
composition of case labels. MSC 6 (not Visual, not C++ ;-) did it ~20 years
ago.
I wouldn't worry about code generated from such constructs until there's
strong evidence of failure...
--
[ See http://www.gotw.ca/resources/clcm.htm for info about ]
[ comp.lang.c++.moderated. First time posters: Do this! ]
|
|
0
|
|
|
|
Reply
|
Balog
|
2/8/2009 10:38:23 PM
|
|
potapov.d@gmail.com wrote:
> On 7 Feb, 20:45, Seungbeom Kim <musip...@bawi.org> wrote:
>> Are you sure? I'd say, the "switch" statement *may* be faster,
>> but it all depends on the details of the implementation;
>> for example, the "switch" statement may be implemented
>> as a series of the "if"..."else"... statements.
>
> We're speaking about compilers here, not the hand-made trash, right?
We're talking about the language here, not compilers.
And the language does not specify how the statements should be
implemented, nor whether one should be faster than the other.
The compiler is free to choose whatever method to do the job.
> So, concerning compilers, would you be so kind to provide the link to
> one, that use the series of "if ... else ..." instead of "switch"? I
> can confirm that VC++6.0 (or later) and GCC 4.1 (or later) doesn't.
Having said the above, it doesn't matter that much, but I tried anyway:
void using_if(int n)
{
if (n == 0)
puts("zero");
else if (n == 1)
puts("one");
else
puts("other");
}
void using_switch(int n)
{
switch (n) {
case 0:
puts("zero"); break;
case 1:
puts("one"); break;
default:
puts("other"); break;
}
}
and GCC 4.1.3 on x86_64 produces chained branches for both.
(Actually, the switch statement produces a somewhat longer code
for a reason I don't obviously understand.)
--
Seungbeom Kim
[ See http://www.gotw.ca/resources/clcm.htm for info about ]
[ comp.lang.c++.moderated. First time posters: Do this! ]
|
|
0
|
|
|
|
Reply
|
Seungbeom
|
2/9/2009 5:09:59 AM
|
|
On Feb 5, 6:05 am, potapo...@gmail.com wrote:
>
> Option 1, "switch" statement is much faster than "if" one:
> Base& Factory::createInstance(int i) {
> switch(i){
> case 1: return C<1>();
> case 2: return C<2>();
> ...
> }
>
> }
>
> Option 2, linear recursive helper function:
> const int max_n = 100;
> template<int n>
> struct helper
> {
> static Base& func(int i)
> {
> return i == n? C<n>() : helper<n+1>::func(i);
> }
>
> };
>
> template<>
> struct helper<max_n>
> {
> static Base& func(int i)
> {
> return C<max_n>();
> }
>
> };
>
> Base& Factory::createInstance(int i) {
> return helper<0>(i);
>
> }
>
<snip>
>
> Base& func0()
> {
> return C<0>();
>
> }
>
> Base& func1()
> {
> return C<1>();
>
> }
>
> Base& func2()
> {
> return C<2>();}
>
> ...
>
> Base& Factory::createInstance(int i) {
> const Base& (*ptrs)()[]={func0,func1,func2,... /* can be filled by
> Boost.Preprocessor too */};
> return ptrs[i]();
>
> }
>
Unfortunately all of those examples fail as they are returning
references to locals that go out of scope.
An appropriate fix for all of them, including the helper version which
I quite like, is to make a local static object like this:
Base & func0()
{
static const C<0> item;
return item;
}
BTW this pattern is very useful in cases where you benchmarked your
code and absolutely need the optimization of template specializations
to factor out variable coefficients into constants.
--jeffk++
www.jdkoftinoff.com
--
[ See http://www.gotw.ca/resources/clcm.htm for info about ]
[ comp.lang.c++.moderated. First time posters: Do this! ]
|
|
0
|
|
|
|
Reply
|
Jeff
|
2/9/2009 5:12:19 AM
|
|
On Feb 9, 3:12 am, Jeff Koftinoff <jeff.koftin...@gmail.com> wrote:
> On Feb 5, 6:05 am, potapo...@gmail.com wrote:
>
>
>
>
>
> > Option 1, "switch" statement is much faster than "if" one:
> > Base& Factory::createInstance(int i) {
> > switch(i){
> > case 1: return C<1>();
> > case 2: return C<2>();
> > ...
> > }
>
> > }
>
> > Option 2, linear recursive helper function:
> > const int max_n = 100;
> > template<int n>
> > struct helper
> > {
> > static Base& func(int i)
> > {
> > return i == n? C<n>() : helper<n+1>::func(i);
> > }
>
> > };
>
> > template<>
> > struct helper<max_n>
> > {
> > static Base& func(int i)
> > {
> > return C<max_n>();
> > }
>
> > };
>
> > Base& Factory::createInstance(int i) {
> > return helper<0>(i);
>
> > }
>
> <snip>
>
> > Base& func0()
> > {
> > return C<0>();
>
> > }
>
> > Base& func1()
> > {
> > return C<1>();
>
> > }
>
> > Base& func2()
> > {
> > return C<2>();}
>
> > ...
>
> > Base& Factory::createInstance(int i) {
> > const Base& (*ptrs)()[]={func0,func1,func2,... /* can be filled by
> > Boost.Preprocessor too */};
> > return ptrs[i]();
>
> > }
>
> Unfortunately all of those examples fail as they are returning
> references to locals that go out of scope.
>
> An appropriate fix for all of them, including the helper version which
> I quite like, is to make a local static object like this:
>
> Base & func0()
> {
> static const C<0> item;
> return item;
>
> }
>
> BTW this pattern is very useful in cases where you benchmarked your
> code and absolutely need the optimization of template specializations
> to factor out variable coefficients into constants.
Do note that the first calls to the above code fragment is not thread-
safe in most implementations of C++03. It will be thread-safe in C+
+0x.
--
[ See http://www.gotw.ca/resources/clcm.htm for info about ]
[ comp.lang.c++.moderated. First time posters: Do this! ]
|
|
0
|
|
|
|
Reply
|
joshuamaurice
|
2/9/2009 3:02:09 PM
|
|
|
12 Replies
135 Views
(page loaded in 0.661 seconds)
Similiar Articles: explicit calling of member template constructor... - comp.lang.c++ ...As for your problem, it is ... 1: type tag, used for template argument deduction // 2 ... type list as any non-template ... struct with const member variable without ... Bad use of stringstream temporary? - comp.lang.c++... while the version with the named local variable works ... stringstream object in a custom class type ... function operator<< with the >>> argument that is void*. The non ... const member functions in classes derived from templates. - comp ...... between templates and const > member functions(and arguments) as ... do with the template aspect of the problem ... to call a non-const member function ... const member variable ... STL allocators, global new/delete using the heap and shared memory ...They seem to think the problem is solved by declaring the STL variable with a ... Has anyone else used a non-default ... pointer; typedef void value_type; template ... Passing va_list by reference to a function - comp.lang.c ...... that for a local variable z of array type (i.e ... modify the ap variable to point to the next argument. Thank you. I didn't understand the problem. ... field of non ... template template specialization - comp.lang.c++.moderated ...... of templates with a single template type ... is used only to give a name to the template argument ... > > Maybe I don't understand the problem, but the primary template alone ... Causes of Reference to non-existent field ... - Computer GroupInput argument "block" is undefined. Error in ... function equalstestb(block) %equalstestb A template for a ... end setup I got similar type of error while trying ... Vista 64 Install - comp.soft-sys.matlabThis indicates a potentially serious problem in ... function or method 'colordef' for input arguments of type ... template of pathdef.m in Matlab\R2010b\local\template ... A "does global variable exist" function - comp.lang.javascript ...To a non-problem of course. :) > > > > The ... You document that the one argument is required and must be a (non- empty ... unix.solaris ... >> I'm defining a local variable ... Undefined XLIB Name - comp.sys.hp48The term "local" (or "temporary") variable generally means a LAM, and there is never a problem using ... program which variable names are templates for ... if the menu is non ... Some text processing questions - comp.lang.vhdl... attention when you switched the problem: variable buf ... Here, again, is a hypothetical (non working code): .... type ... file to VHDL code using a test bench template ... Multiple definition and specialization of static data member ...----- I encountered a problem in a header file like the following: template <typename ... external linkage, class template, non ... cast ... to check the type of a variable over ... Syntax error trying to return scalar value from query in stored ...LIMIT takes one or two numeric arguments, which must ... You need to declare a local variable: DECLARE whatever ... the cursor approach is much quicker than the non ... Could anyone give me the spice-mode.el - comp.emacsHi, All I am new to *NIX and I am thinking of writing spice code under Emacs. However, I have no idea of Emacs Lisp. Hence, I could not write a packa... naming convention for class attributes (member data)? - comp.lang ...... was for attributing usage of variable MS did indicate type with it. ... overhead and scalability issues as all ... for "instance" aFoo // for function arguments foo // local ... c++ - local variable as non-type template argument - Stack Overflowlocal variable as non-type template argument ... local variable cannot be used as a non-type argument* Any solutions for this problem? ... be a non-type template argument ... local variable as non-type argument | DaniWebThe problem is that I get the error:template parameter 'T_MEMBER_FUNCTION' : 'MemberFunctionPointer' : a local variable cannot be used as a non-type argument 7/30/2012 8:20:56 AM
|