采用继承类的C++非类型模板参数

j4x*_*j4x 5 c++ inheritance templates template-specialization

我希望能够传递从DBMetaData另一个类的非类型模板参数继承的对象的引用,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;
}
Run Code Online (Sandbox Code Playgroud)

我可以编译并运行上面的示例,我需要显式指定继承的类型.

如果我尝试编译它定义DO_WHAT_I_WANT(我想将类型的引用 - 或指针 - 传递给DBMetaData任何继承类的对象),我得到错误:

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
Run Code Online (Sandbox Code Playgroud)

为什么我不能通过_u1,那是DBMetaData_NTDBMetaData作为参数继承的类型DBVar< _md_u1 > _u1;

有什么方法可以得到我想要的东西吗?

谢谢!


编辑:

用@ecatmur建议用函数指针替换模板参数解决了我的问题,我必须注意,我的代码更易读.

#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;
}
Run Code Online (Sandbox Code Playgroud)

eca*_*mur 5

不幸的是没有。根据 14.3.2模板非类型参数,第 1 段:

非类型、非模板模板参数的模板参数应为以下之一:[...]

  • 一个常量表达式,指定具有静态存储持续时间的对象的地址 [...],表示(忽略括号)为& id-expression,但如果相应的模板参数是引用&,则应省略 [...] 。

根据同一节第 5 段,不允许进行派生到基数的转换:

  • 对于对象类型引用的非类型模板参数,不应用任何转换。引用所引用的类型可能比template-argument的类型(否则相同)更具 cv 限定性。template -parameter直接绑定到template-argument,它应该是一个左值。

这也意味着不允许进行强制转换,因为它不是 [ &] id-expression形式,并且不会产生左值。

根据您想要完成的任务,您也许能够通过手动模拟多态性来实现类似的结果,例如初始化为_md_u1设置适当的 vtable 指针或表的函数的返回值。