2009-10-21 132 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 

更多的模板和类型名称的例子。