2012-11-28 42 views
5

我希望能夠通過從DBMetaData繼承作爲另一個類的無類型模板參數的對象的引用,DBVarC++無類型模板參數服用繼承的類

#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; 
} 

我可以編譯和運行上面的例子我需要顯式指定繼承類型。

如果我嘗試編譯它定義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 

爲什麼能」 t我通過_u1,即DBMetaData_NT類型,它繼承DBMetaData作爲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; 
} 

回答

4

不幸的不是。每14.3.2 模板非類型參數,第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.

派生到基轉換是允許的,每相同部分第5段:

  • 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.

這也意味着不允許演員陣容,因爲這不是[&] id-表達式,並且不產生左值。

根據您試圖完成的內容,您可能能夠通過手動模擬多態性來獲得類似的結果,例如,將_md_u1初始化爲設置適當的vtable指針或表的函數的返回值。

+0

就是這樣。一個函數。它解決了我的問題。我使用基於功能的解決方案編輯了我的問題。謝謝! – j4x

+0

我想知道,如果術語「協方差」在這裏適用。它是已知的(http:// stackoverflow。com/questions/2203388/c-templates-polymorphism)C++模板不是協變的。看起來可以這樣說,模板非類型參數也不是協變的。 – pfalcon

1

你可以用C++ 11的decltype和像下面的宏做:

#define DBVAR(metadata) DBVar<decltype(metadata), metadata> 

現在,定義一個變量:

DBVAR(_md_u1) _u1; 

希望這有助於。

編輯:說實話我不喜歡你的方法。我寧願去使用靜態元數據成員函數或基於非模板的多態性。