Sun Studio 12 中的模板编译错误

Posted

技术标签:

【中文标题】Sun Studio 12 中的模板编译错误【英文标题】:Template compilation error in Sun Studio 12 【发布时间】:2012-07-02 15:11:04 【问题描述】:

我们正在迁移到 Sun Studio 12.1 并使用新的编译器 [ CC: Sun C++ 5.10 SunOS_sparc 2009/06/03 ]。我在编译使用早期版本的 Sun 编译器 [CC: Sun WorkShop 6 update 2 C++ 5.3 2001/05/15] 编译良好的代码时遇到编译错误。

这是我得到的编译错误。

“Sample.cc”:错误:找不到 LoopThrough(int[2]) 的匹配项 在 main() 中需要。 1 检测到错误。 *** 错误代码 1。

代码:

#include <iostream> 

#define PRINT_TRACE(STR) \
std::cout << __FILE__ << ":" << __LINE__ << ":" << STR << "\n";

template<size_t SZ>
void LoopThrough(const int(&Item)[SZ])

    PRINT_TRACE("Specialized version");
    for (size_t index = 0; index < SZ; ++index)
    
        std::cout << Item[index] << "\n";
    



/*     
    template<typename Type, size_t SZ>
    void LoopThrough(const Type(&Item)[SZ])
    
        PRINT_TRACE("Generic version");        
    
 */  



int main()

    
       int arr[] =  1, 2 ;
       LoopThrough(arr);    
    

如果我用通用版本取消注释代码,代码编译得很好并且通用版本被调用。在禁用扩展的 MSVC 2010 和 ideone here 的情况下,我没有看到这个问题。 调用该函数的专用版本。现在的问题是,这是 Sun Compiler 中的错误吗?

如果是,我们如何提交错误报告?

【问题讨论】:

删除 const 可能会起作用吗? 如果最新版本的clang、gcc、comeau 和msvc 一致,则可能是SunCC 中的一个错误。另请注意,SunCC 因错误而闻名。这就引出了一个问题:为什么不使用 gcc? 我希望您同意我的观点,即切换供应商的依赖项太多了。我只是一台非常大的机器上的螺丝钉:-) @Jagannath:当代码是标准 C++ 时,可能的依赖项应该是最少的......如果你使用的是 SunCC 特定的扩展,那么...... 对此不同意。如果使用标准,应该没有依赖关系。使用 gcc/4.7.0 编译良好,调用专用版本。 【参考方案1】:

在这种情况下,编译器没有遵循标准并且有问题。让我们回顾一下相关部分。

首先从 13.3/3 我们有:

...

——首先,候选函数的一个子集——那些具有 适当数量的参数并满足某些其他条件——是 选择以形成一组可行的功能(13.3.2)。

——然后​​根据隐式选择最佳可行函数 将每个参数与 每个可行函数的对应参数。

所以这两个函数都有相同数量的参数并且被认为是候选函数。现在我们必须找到最好的可行函数,在

13.3.3:

让 ICSi(F) 表示隐式转换序列 列表中的第 i 个参数为可行的第 i 个参数的类型 函数 F. 13.3.3.1 定义了隐式转换序列和 13.3.3.2 定义了一个隐式转换序列是更好的转换序列或更差的转换序列的含义 另一个

那么我们有

鉴于这些定义,一个可行的函数 F1 被定义为 如果所有参数都比另一个可行的函数 F2 更好的函数 i,ICSi(F1)不是比ICSi(F2)差的转换序列,那么

——对于某些参数 j,ICSj(F1) 是比 ICSj(F2),或者,如果不是,

——F1 是一个非模板函数,F2 是一个 模板函数特化,或者,如果不是,

——F1 和 F2 是 模板函数,F1的函数模板更多 根据偏序,比 F2 的模板更专业 14.5.5.2 中描述的规则,或者,如果不是,

第一个规则的两个函数相等(添加 const),第二个规则不适用(都是模板)。所以我们转向第三条规则。从 14.5.5.2(如果需要,我会引用)我们了解到该函数的 const int 版本比 const Item 版本更专业,因此最佳匹配是 const int 重载,然后应该调用.

你最好的临时修复可能是第二次超载:

template<size_t SZ>
void LoopThrough(int (&Item)[SZ])

    LoopThrough(static_cast<const int (&)[SZ]>(Item));

【讨论】:

【参考方案2】:

你的编译器有问题。两种重载都推导出了它们的模板参数,并且重载决议应该选择最专业的一个。那么除了获得一个新的编译器,你还能做什么呢?

首先,认识到 - 即使使用符合标准的编译器 - 使用不同的函数模板重载通常也不是一个好主意。参见例如C++ Coding Standards: 101 Rules, Guidelines, and Best Practices 的第 66 项,作者 Herb Sutter 和 Andrei Alexandrescu。

幸运的是,该项目还提出了一个可能的解决方案。您所要做的就是定义一个函数模板,并让该函数模板将工作委托给一个类模板函数对象。然后,您可以为 ints 部分专门化此类模板。

#include <iostream> 

#define PRINT_TRACE(STR) \
std::cout << __FILE__ << ":" << __LINE__ << ":" << STR << "\n";

namespace detail     

// primary template
template<typename Type, size_t SZ>
class LoopThroughHelper

public:
    void operator()(const Type(&Item)[SZ]) 
    
        PRINT_TRACE("Generic version");        
    
; 

// partial specialization for int arrays
template<size_t SZ>
class LoopThroughHelper<int, SZ>

public:
    void operator()(const int(&Item)[SZ]) 
    
        PRINT_TRACE("Specialized version");
        for (size_t index = 0; index < SZ; ++index)
        
            std::cout << Item[index] << "\n";
        
    
; 

 // namespace detail

// one function template to rule them all
template<typename Type, size_t SZ>
void LoopThrough(const Type(&Item)[SZ])

     detail::LoopThroughHelper<Type, SZ>()(Item);        


int main()

    
       int arr[] =  1, 2 ;
       LoopThrough(arr);    
    

最有可能的是,编译器会内联对函数对象的调用并完全优化掉临时对象。希望您的编译器也能正确实现类模板的部分特化。

Ideone 上的输出

【讨论】:

OP 的问题特别是只有一个模板无法编译,因为编译器不会将非常量数组绑定到 const 数组参数。 @MarkB 不管怎样,对专门的函数对象有额外的间接而不是多个函数重载是一种很好的风格。

以上是关于Sun Studio 12 中的模板编译错误的主要内容,如果未能解决你的问题,请参考以下文章

错误记录Android Studio 编译报错 ( Invalid Gradle JDK configuration found )

错误记录Android Studio 编译信息输出乱码

Sun Studio 和“”,第 1 行:非法标志 (-)

更新 Visual Studio 2017,现在出现编译错误 C7510:“回调”:使用依赖模板名称必须以“模板”为前缀

使用嵌套模板化变量解决 Visual Studio 内部编译器错误

android Studio 项目里报这个错误,是啥原因啊。编译时报错。