I want to be able to pass references of objects inherited from DBMetaData
as a nontype template argument of another class, DBVar
:
#include <iostream>
class DBMetaData
{
public:
virtual const char *description( ) const = 0;
};
class DBMetaData_NT
: public DBMetaData
{
public:
const char *description( ) const
{ return "Useless description."; }
};
#if DO_WHAT_I_WANT
template< const DBMetaData &Metadata >
#else
template< typename MetadataType,
const MetadataType &Metadata >
#endif // DO_WHAT_I_WANT
class DBVar
{
public:
/// Descrição da variavel.
const char *description( ) const
{ return Metadata.description( ); }
};
DBMetaData_NT _md_u1;
#if DO_WHAT_I_WANT
DBVar< _md_u1 > _u1;
#else
DBVar< DBMetaData_NT, _md_u1 > _u1;
#endif // DO_WHAT_I_WANT
int main( )
{
std::cout << "_md_u1.description( ) = " << _md_u1.description( ) << std::endl;
std::cout << "_u1.description( ) = " << _u1.description( ) << std::endl;
return 0;
}
I can compile and run the above example but I need to explicitly specify teh inherited type.
If I try to compile it defining DO_WHAT_I_WANT
(I want to pass a reference - or pointer - of type DBMetaData
to an object of any inherited class), I get the error:
templ_inh_arg.cpp:36:15: error: could not convert template argument ‘_md_u1’ to ‘const DBMetaData&’
templ_inh_arg.cpp:36:20: error: invalid type in declaration before ‘;’ token
Why can't I pass _u1
, that is of type DBMetaData_NT
that inherits from DBMetaData
as parameter for DBVar< _md_u1 > _u1;
?
Is there any way to get what I want?
Thanks!
EDIT:
Replacing the template parameter with a function pointer, as suggested by @ecatmur solved my problem and, I must note, turned my code a little more readable.
#include <iostream>
class DBMetaData
{
public:
/// Descrição da variavel.
virtual const char *description( ) const = 0;
};
class DBMetaData_NT
: public DBMetaData
{
public:
const char *description( ) const
{ return "Useless description."; }
};
typedef const DBMetaData &( *metadata )( );
template< metadata Metadata >
class DBVar
{
public:
/// Descrição da variavel.
const char *description( ) const
{ return Metadata( ).description( ); }
};
const DBMetaData & _md_u1_metadata( )
{
static const DBMetaData_NT _md_u1;
return _md_u1;
}
DBVar< _md_u1_metadata > _u1;
int main( )
{
std::cout << "_md_u1_metadata( ).description( ) = " << _md_u1_metadata( ).description( ) << std::endl;
std::cout << "_u1.description( ) = " << _u1.description( ) << std::endl;
return 0;
}
Unfortunately not. Per 14.3.2 Template non-type arguments, paragraph 1:
A template-argument for a non-type, non-template template-parameter shall be one of: [...]
- a constant expression that designates the address of an object with static storage duration [...], expressed (ignoring parentheses) as
&
id-expression, except that the&
[...] shall be omitted if the corresponding template-parameter is a reference.
Derived-to-base conversions are not permitted, per paragraph 5 of the same section:
- For a non-type template-parameter of type reference to object, no conversions apply. The type referred to by the reference may be more cv-qualified than the (otherwise identical) type of the template-argument. The template-parameter is bound directly to the template-argument, which shall be an lvalue.
This also means that a cast is not permitted, as this is not of the form [&
] id-expression, and does not yield an lvalue.
Depending on what you're trying to accomplish, you may be able to achieve a similar result through manually simulating polymorphism e.g. having _md_u1
initialised as the return value of a function which sets up an appropriate vtable pointer or table.
You can do it with C++11's decltype
and a macro like following:
#define DBVAR(metadata) DBVar<decltype(metadata), metadata>
Now, to define a variable:
DBVAR(_md_u1) _u1;
Hope this helps.
EDIT: To be honest I don't like your approach. I'd rather go with static metadata member functions or non-template based polymorphism.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With