3

我正在查看一些大量使用模板的代码。它在 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>for T=void 的专业化,它没有声明 a size_type。我认为size_type是所有分配器的必需成员?

所以现在的问题是,在语法分析过程中,什么可能会严重破坏 VS,以至于它抱怨完全不相关的非问题是错误,你如何调试这样的代码?

ps 对于那些有太多空闲时间的人,我试图在 VS 中编写的代码是 Kevin SoppBoost 沙箱中的 mp_math,它基于libtommath

4

4 回答 4

6

我认为这可能是由几种情况引起的

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

我怀疑 Visual C++ 无法进行此查找,而是会出错。正如其他人所提到的,您可以明确限定成员函数定义中的类型名称。然后类型是依赖的,这将触发编译器的机制来延迟名称查找直到实例化。

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)
{
    // ....
}
于 2009-08-12T23:51:18.650 回答
1

这里有一些有趣的东西 - 这个人

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

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

于 2009-08-12T23:34:21.960 回答
0

哪一行导致第一个错误?

在此定义中是否使用了 unbounded_int_type:

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)
{
    // ....
}

?

于 2009-08-12T23:25:59.840 回答
0

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

从这个角度思考,你怎么能确定那unbounded_int_type::digit_type是一个类型?这取决于是哪种类型unbounded_int_typetypename因此,您可以通过添加关键字来消除歧义。

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)
{
    // ....
}

唯一的变化是在这里 - 我添加了typename关键字。

类型定义
typename make_signed< typename unbounded_int_type::digit_type >::type integral_type;
于 2009-08-21T16:08:42.373 回答