代码之家  ›  专栏  ›  技术社区  ›  KTC

模板的成员typedef在vs而不是gcc中未声明的标识符参数中使用

  •  3
  • KTC  · 技术社区  · 15 年前

    我在看一些大量使用模板的代码。它在gcc上编译得很好,但在vs上编译不好(在2003-2010 beta 1上测试),在语法分析期间失败。不幸的是,我对代码结构不太了解,无法减少问题并只在几行中重现,所以我只能猜测原因。我希望这里有人能给我指明正确的方向。

    我们有

    template< class UInt, typename IntT,
        bool is_signed = std::numeric_limits<IntT>::is_signed >
    struct uii_ops_impl;
    
    // ....
    
    template<class UInt>
    struct uii_ops_impl< UInt,
        typename make_signed<typename UInt::digit_type>::type, true >
    {
        typedef UInt unbounded_int_type;
        typedef typename make_signed< typename unbounded_int_type::digit_type >::type
            integral_type;
    
        // ...
    
        static void add(unbounded_int_type& lhs, integral_type rhs);
    
        // ...
    };
    
    template<class UInt>
    void uii_ops_impl<
        UInt, typename make_signed<typename UInt::digit_type>::type,
        true >::add(unbounded_int_type& lhs, integral_type rhs)
    {
        // ....
    }
    

    在vs上编译时,它返回的第一条错误消息(在许多错误消息中)是

    :错误C2065:' unbounded_int_type ':未声明的标识符

    我是说, 指向typedef 呵呵?-S

    编辑:

    好像有什么关系

    typename make_signed<typename UInt::digit_type>::type
    

    用作模板参数。在其余的代码中,成员函数参数中使用的类似typedef可以很好地编译。到目前为止,我能看到的唯一区别是,其他任何情况都没有将上面的行作为模板参数。 make_signed 来自boost.typetraits。

    编辑:

    好吧,也许不是这样,因为完全相同的事情是在另一个文件中完成的,在那里它编译得很好。隐马尔可夫模型。。。

    赏金编辑:

    好吧,我认为这一点很明显,问题不在于编译器抱怨的地方。只有两个成员函数在该特定点上的定义失败。结果是显式地限定参数 编译。唯一直接的解决方案是定义内联函数。通过语法分析。但是,当尝试重新设置模板时,vs现在失败了,因为 std::allocator<void> 没有一个 size_type 成员。结果发现vs有一个专门的 std::allocator<T> 对于t=无效,不声明 SiZe型 .我想 SiZe型 是所有分配器的必需成员吗?

    所以现在的问题是,在语法分析过程中,有什么可能会弄错,以至于它抱怨完全无关的非问题是错误,您如何调试这些代码?

    另外,对于那些有太多时间可供使用的人来说,我想在vs中使用的代码是凯文·索普的 mp_math 在Boost的沙盒中, libtommath .

    4 回复  |  直到 15 年前
        1
  •  6
  •   Johannes Schaub - litb    15 年前

    我认为这可能是由一些情况引起的

    • unbounded_int_type 是一个 non-dependent 类型(定义于 14.6.2.1 )
    • 它的声明出现在类模板中。因为它是非依赖的,所以必须在定义成员函数时将其名称解析为声明。

    我怀疑VisualC++是无法进行查找的,而不是错误。正如其他人提到的,您可以在成员函数定义中显式限定类型名。然后这些类型是依赖的,这将触发编译器的机制,将名称查找延迟到实例化。

    template<class UInt>
    void uii_ops_impl<
        UInt, typename make_signed<typename UInt::digit_type>::type,
        true >::add(typename
                    /* repeat-that-beast uii_ops...true> here */
                       ::unbounded_int_type& lhs, 
                    typename /* and here too */::integral_type rhs)
    {
        // ....
    }
    
        2
  •  1
  •   Community Michael Schmitz    7 年前

    有件有趣的事-这个家伙

    在MSVC中遇到一个与您所看到的非常相似的错误-除了 使用 一个typedef为他解决了这个问题。

    我仍然不知道如何处理他遇到的问题(或者你遇到的问题)。正如您所说,您发布的小片段不会重新生成错误(给定一个简单的 make_signed<> 允许的模板 make_signed<>::type 可编译的)

        3
  •  0
  •   jon hanson    15 年前

    哪一行导致第一个错误?

    此定义中是否使用了无边界的“int”类型:

    template<class UInt>
    void uii_ops_impl<
        UInt, typename make_signed<typename UInt::digit_type>::type,
        true >::add(unbounded_int_type& lhs, integral_type rhs)
    {
        // ....
    }
    

    需要完全合格:

    template<class UInt>
    void uii_ops_impl<
        UInt, typename make_signed<typename UInt::digit_type>::type,
        true >::add(uii_ops_impl<UInt, etc ,true>::unbounded_int_type& lhs, integral_type rhs)
    {
        // ....
    }
    

    ?

        4
  •  0
  •   Jorge Ferreira    15 年前

    你必须在这方面帮助编译器一点。 . 你必须使用 typename 关键字,因为您有一个引用类型并依赖于模板参数的限定名。

    从这个角度考虑,你怎么能确定 unbounded_int_type::digit_type 是一种类型吗?这取决于哪种类型 unbounded_int_type . 因此,通过添加 类别名 关键字。

    template< class UInt, typename IntT,
    bool is_signed = std::numeric_limits<IntT>::is_signed >
    struct uii_ops_impl;
    
    // ....
    
    template <class T>
    struct make_signed
    {
        typedef T type;
    };
    
    template<class UInt>
    struct uii_ops_impl< UInt,
        typename make_signed<typename UInt::digit_type>::type, true >
    {
        typedef UInt unbounded_int_type;
        typedef typename make_signed< typename unbounded_int_type::digit_type >::type
            integral_type;
    
        // ...
    
        static void add(unbounded_int_type& lhs, integral_type rhs);
    
        // ...
    };
    
    template<class UInt>
    void uii_ops_impl<
    UInt, typename make_signed<typename UInt::digit_type>::type,
    true >::add(unbounded_int_type& lhs, integral_type rhs)
    {
        // ....
    }
    

    唯一的变化是这里-我添加了 类别名 关键字。

    typedef
    typename make_signed< typename unbounded_int_type::digit_type >::type             integral_type;