2009-10-21 94 views
4

其實我用intel編譯器編譯某個庫時遇到了問題。模板問題('typename'爲非模板函數參數)

這個相同的庫已經用g ++編譯正確。

問題是由模板引起的。 我想了解是 **typename**宣佈爲內部函數體不是模板函數的參數和變量聲明

例如:

void func(typename sometype){.. 
... 
typename some_other_type; 
.. 
} 

編譯這種代碼農產品下面的錯誤(英特爾) (GCC不要求): 我有以下錯誤

../../../libs/log/src/attribute_set.cpp(415): error: no operator "!=" matches these operands 
      operand types are: boost::log_st::basic_attribute_set<wchar_t>::iter<'\000'> != boost::log_st::basic_attribute_set<wchar_t>::iter<'\000'> 
     while (begin != end) 
       ^
      detected during instantiation of "void boost::log_st::basic_attribute_set<CharT>::erase(boost::log_st::basic_attribute_set<CharT>::iter<'\000'>, boost::log_st::basic_attribute_set<CharT>::iter<'\000'>) [with CharT=wchar_t]" at line 438 

../../../boost/log/attributes/attribute_set.hpp(115): error: no operator "!=" matches these operands 
      operand types are: boost::log_st::basic_attribute_set<wchar_t>::iter<'\000'> != boost::log_st::basic_attribute_set<wchar_t>::iter<'\000'> 
       if (it != m_pContainer->end()) 

我想什麼要了解的是類型名的董事會內部使用y函數,參數聲明。

例:

template< typename CharT > 
struct basic_attribute_values_view<CharT>::implementation 
{ 

public: 
.. 
.. 
void adopt_nodes(**typename attribu**te_set_type::const_iterator& it, **typename attribut**e_set_type::const_iterator end) 
    { 
     for (; it != end; ++it) 
      push_back(it->first, it->second.get()); 
    } 
在不同的文件

我有:

template< typename CharT > 
class basic_attribute_set 
{ 
    friend class basic_attribute_values_view<CharT>; 

    //! Self type 
    typedef basic_attribute_set<CharT> this_type; 

public: 
    //! Character type 
    typedef CharT char_type; 
    //! String type 
    typedef std::basic_string<char_type> string_type; 
    //! Key type 
    typedef basic_slim_string<char_type> key_type; 
    //! Mapped attribute type 
    typedef shared_ptr<attribute> mapped_type; 

    //! Value type 
    typedef std::pair< const key_type, mapped_type > value_type; 
    //! Allocator type 
    typedef std::allocator<value_type> allocator_type; 
    //! Reference type 
    **typedef typename allocator_type::reference reference;** 
+0

這會更容易......如果我們有產生編譯器錯誤的代碼(以指示的行引入)。請注意,使用'**'作爲語法不適用於代碼塊。 –

+0

我的示例中的所有迭代器!=動作都會產生相似的錯誤,所以在我的第一個代碼示例中它將是(it!= end;)行。 – bua

回答

12

您需要使用typename的所謂稱爲「依賴類型」。這些是依賴於模板參數的類型,在模板實例化之前不知道。這也可能是最好用一個例子說明:

struct some_foo { 
    typedef int bar; 
}; 

template< typename Foo > 
struct baz { 
    typedef Foo::bar barbar; // wrong, shouldn't compile 

    barbar f(); // would be fine if barbar were a type 

    // more stuff... 
}; 

typedef定義barbar是一個需要typename爲了使編譯器能夠檢查公然語法錯誤模板之前被實例化一個具體類型。原因是,當編譯器第一次看到模板(當它沒有用具體的模板參數實例化)時,編譯器不知道Foo::bar是否是一種類型。對於所有它知道,我可能意圖baz要與類型的實例化這樣一個

struct some_other_foo { 
    static int bar; 
}; 

在這種情況下Foo::bar會提到一個對象,不是一個類型,而baz::bar的定義是語法無稽之談。在不知道Foo::bar是否指向一個類型的情況下,編譯器沒有機會檢查baz中的任何內容,這些內容直接或間接使用barbar,即使是最愚蠢的錯別字,直到baz被實例化。使用合適的typenamebaz看起來是這樣的:

template< typename Foo > 
struct baz { 
    typedef typename Foo::bar barbar; 

    barbar f(); 

    // more stuff... 
}; 

現在,編譯器至少知道Foo::bar應該是一個類型,這使得barbar類型名稱的名稱了。所以f()的聲明也是合法的。

順便說一句,有一個類似的問題與模板,而不是類型:

template< typename Foo > 
struct baz { 
    Foo::bar<Foo> create_wrgl(); // wrong, shouldn't compile 
}; 

當編譯器「看見」 Foo::bar它不知道它是什麼,所以bar<Foo也可以同樣是一個比較,讓編譯器對尾隨的>感到困惑。在這裏,你需要給編譯器一個暗示,Foo::bar應該是一個模板的名稱:

template< typename Foo > 
struct baz { 
    Foo::template bar<Foo> create_wrgl(); 
}; 

當心:++仍然沒有實施適當的兩階段查找(本質值得注意的是視覺C:它不會真正檢查模板,直到它們被實例化)。因此它經常接受錯過typenametemplate的錯誤代碼。

+2

+1提及兩階段查找。因此建議:如果可能,嘗試用至少2個不同的編譯器編譯你的代碼。 – Francesco

3

typename關鍵字的一點是要告訴編譯器,什麼是類型名,在情況下這不是明顯。就拿這個例子:

template<typename T> 
void f() 
{ 
    T::foo * x; 
} 

T::foo一個類型,這意味着我們宣佈一個指針,或者是T::foo一個靜態變量,和我們正在做乘法?

因爲編譯器不知道在讀取模板時T可能是什麼,所以它不知道這兩種情況中的哪一種是正確的。

該標準規定編譯器應該承擔後一種情況下,只有解釋T::foo作爲類型名,如果它是由typename關鍵字之前,像這樣:

template<typename T> 
void f() 
{ 
    typename T::foo* x; //Definitely a pointer. 
} 
0

在你的代碼:

void func(typename sometype) 
{ 
    .....typename some_other_type; 
    .. 
} 

如果上面的代碼是不是一個模板的一部分,那麼它可以不使用G ++編譯,除非舊版本克++。

由於我的經驗,FC9或GNU C/++版本4.2倍將其報告爲一個錯誤,它會抱怨:

typename only can be used in template code 

而FC8或GNU C/++ 4.1倍可能不會。

請參閱

http://code.google.com/p/effocore/source/browse/trunk/devel/effo/codebase/addons/inl/include/ringed_inl.h 
and 
http://code.google.com/p/effocore/source/browse/trunk/devel/effo/codebase/addons/inl/include/cont_inl.h 

更多的模板和類型名稱的例子。