模板问题(“类型名称”不是模板函数参数)

发布于 2024-08-08 08:51:20 字数 2449 浏览 5 评论 0 原文

实际上,我在使用英特尔编译器编译某些库时遇到问题。

该库已使用 g++ 正确编译。

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

示例:

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

编译此类代码会产生以下错误(intel),(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())

我想了解的是函数体内的类型名、参数声明的用法。

例如:

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;**

Actually I've a problem with compiling some library with intel compiler.

This same library has been compiled properly with g++.

Problem is caused by templates.
What I'd like to understand is the declaration of
**typename** as not template function parameter and variable declaration inside function body

example:

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

Compilation this kind of code produce following errors (intel),(gcc doesn't claim):
I've got following errors

../../../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())

What I'd like to understand is the usage of the typename inside the body of functions, parameter declarations.

ex.:

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());
    }

in different file I've:

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;**

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(3

新雨望断虹 2024-08-15 08:51:21

您需要使用 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...
};

定义 barbar 的 typedef 需要一个 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 应该是 a 的名称type,这也使 barbar 成为类型名称。因此 f() 的声明在语法上也是正确的。

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

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

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

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

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

You need to use typename for so-called "dependent types". Those are types that depend on a template argument and are not known until the template is instantiated. It's probably best explained using an example:

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

That typedef defining barbar is one that requires a typename in order for the compiler to be able to check the template for blatant syntactic errors before it is instantiated with a concrete type. The reason is that, when the compiler sees the template for the first time (when it's not instantiated with concrete template parameters yet), the compiler doesn't know whether Foo::bar is a type. For all it know, I might intent baz to be instantiated with types like this one

struct some_other_foo {
  static int bar;
};

in which case Foo::bar would refer to an object, not a type, and the definition of baz::bar would be syntactic nonsense. Without knowing whether Foo::bar refers to a type, the compiler has no chance to check anything within baz that's directly or indirectly using barbar for even the most stupid typos until baz is instantiated. Using the proper typename, baz looks like this:

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

  barbar f();

  // more stuff...
};

Now the compiler at least knows that Foo::bar is supposed to be the name of a type, which makes barbar a type name, too. So the declaration of f() is syntactical OK, too.

By the way, there's a similar problem with templates instead of types:

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

When the compiler "sees" Foo::bar it doesn't know what it is, so bar<Foo could just as well be a comparison, leaving the compiler confused about the trailing >. Here, too, you need to give the compiler a hint that Foo::bar is supposed to be the name of a template:

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

Beware: Notably Visual C++ still doesn't implement proper two-phase lookup (in essence: it doesn't really check templates until they are instantiated). Therefor it often accepts erroneous code that misses a typename or a template.

梦醒时光 2024-08-15 08:51:21

typename 关键字的作用是在不明显的情况下告诉编译器某物是类型名。举个例子:

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

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

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

标准规定编译器应假定后一种情况,并且仅将前面带有 typename 关键字的 T::foo 解释为类型名,如下所示:

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

The point of the typename keyword is to tell the compiler that something is a typename, in situations where it's not obvious. Take this example:

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

Is T::foo a type, meaning we are declaring a pointer, or is T::foo a static variable, and we are doing a multiplication?

Since the compiler has no idea of what T could be at the time it reads the template, it has no idea which of the two cases is correct.

The standard dictates that the compiler should assume the latter case, and only interpret T::foo as a typename if it is preceded by the typename keyword, like this:

template<typename T>
void f()
{
    typename T::foo* x; //Definitely a pointer.
}
等数载,海棠开 2024-08-15 08:51:21

根据您的代码:

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

如果上述代码不是模板的一部分,则无法使用 g++ 编译它,除非旧版本的 g++。

根据我的经验,FC9 或 GNU C/++ 4.2x 版本会将其报告为错误,它会抱怨:

typename only can be used in template code

而 FC8 或 GNU C/++ 4.1x 可能不会。

请参阅

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

更多模板和类型名称示例。

Upon your code:

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

If the above code is not a part of a template, then it cannot be compiled using g++, unless the old version of g++.

As my experienced, FC9 or GNU C/++ version 4.2x will report it as an error, it'll complain:

typename only can be used in template code

while FC8 or GNU C/++ 4.1x may not.

Please see

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

for more template and typename examples.

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文