模板问题('typename'不是模板函数参数)

bua*_*bua 4 c++ boost generic-programming

实际上我用intel编译器编译一些库时遇到了问题.

使用g ++正确编译了相同的库.

问题是由模板引起的.我想要理解的是 **typename**函数体内的模板函数参数和变量声明的声明

例:

void func(typename sometype){..
...
typename some_other_type;
..
}
Run Code Online (Sandbox Code Playgroud)

编译这种代码产生以下错误(英特尔),(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())
Run Code Online (Sandbox Code Playgroud)

我想要理解的是在函数体内使用typename,参数声明.

例:

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

我在不同的文件中:

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

sbi*_*sbi 13

您需要使用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...
};
Run Code Online (Sandbox Code Playgroud)

typedef定义barbar需要一个typename,以便编译器能够使用具体类型实例化之前检查模板是否存在明显的语法错误.原因是,当编译器第一次看到模板时(当它还没有用具体的模板参数实例化时),编译器不知道是否Foo::bar是一个类型.尽管如此,我可能打算baz用类似这样的类型进行实例化

struct some_other_foo {
  static int bar;
};
Run Code Online (Sandbox Code Playgroud)

在这种情况下,Foo::bar它将引用一个对象,而不是一个类型,并且定义baz::bar将是句法无意义.在不知道是否Foo::bar引用类型的情况下,编译器没有机会baz直接或间接地检查任何内容barbar,即使是最愚蠢的拼写错误,直到baz实例化为止.使用正确typename,baz看起来像这样:

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

  barbar f();

  // more stuff...
};
Run Code Online (Sandbox Code Playgroud)

现在编译器至少知道Foo::bar应该barbar是类型的名称,它也是一个类型名称.所以声明f()也是合法的.

顺便说一句,模板而不是类型有类似的问题:

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

当编译器"看到"时Foo::bar它不知道它是什么,所以bar<Foo也可以进行比较,让编译器对尾随感到困惑>.在这里,您还需要为编译器提供一个Foo::bar应该是模板名称的提示:

template< typename Foo >
struct baz {
  Foo::template bar<Foo> create_wrgl();
};
Run Code Online (Sandbox Code Playgroud)

注意:值得注意的是,Visual C++仍然没有实现正确的两阶段查找(实质上:在实例化之前它并不真正检查模板).因此,它经常接受错过a typename或a的错误代码template.

  • +1提及两阶段查找.因此建议:如果可能的话尝试使用至少2个不同的编译器编译代码. (2认同)

CAd*_*ker 6

该点typename关键字告诉编译器,什么是类型名,在这不是很明显的情况。拿这个例子:

template<typename T>
void f()
{
    T::foo * x;
}
Run Code Online (Sandbox Code Playgroud)

T::foo一个类型,意味着我们正在声明一个指针,还是T::foo一个静态变量,我们正在做乘法?

由于编译器在读取模板时不知道 T 可能是什么,因此它不知道这两种情况中哪一种是正确的。

该标准规定编译器应该假设后一种情况,并且只有T::footypename关键字前面时才将其解释为类型名,如下所示:

template<typename T>
void f()
{
    typename T::foo* x; //Definitely a pointer.
}
Run Code Online (Sandbox Code Playgroud)