Sun Studio 12中的模板编译错误

时间:2012-07-02 15:11:05

标签: c++ templates overload-resolution partial-specialization sunstudio

我们正在迁移到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);    
    }
}

如果我使用Generic版本取消注释代码,则代码编译良好,并调用泛型版本。我没有看到禁用扩展的MSVC 2010的这个问题,以及与ideone here相同的情况。 调用该函数的专用版本。现在的问题是,这是Sun编译器中的一个错误吗?

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

2 个答案:

答案 0 :(得分:2)

在这种情况下,编译器没有遵循标准并且是错误的。我们来看看相关部分。

首先从13.3 / 3我们得到:

  

...

     

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

     

- 然后根据隐含选择最佳可行功能   转换序列(13.3.3.1)需要匹配每个参数   每个可行功能的相应参数。

因此两个函数具有相同数量的参数并被视为候选。现在我们必须找到最好的可行功能,

13.3.3:

  

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

然后我们

  

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

     

- 对于某些参数j,ICSj(F1)是一个更好的转换序列   ICSj(F2),或者,如果不是,

     

- F1是非模板函数,F2是a   模板函数专业化,或者,如果不是,

     

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

答案 1 :(得分:1)

您的编译器有问题。两个重载都推导出了模板参数,重载决策应该选择最专业的一个。所以除了获得一个新的编译器,你能做什么?

首先,实现这一点很有帮助 - 即使使用符合要求的编译器 - 使用不同的函数模板重载通常也不是一个好主意。参见例如Herb Sutter和Andrei Alexandrescu撰写的C++ Coding Standards: 101 Rules, Guidelines, and Best Practices项目66。

幸运的是,该项目也提出了一个可能的解决办法。您所要做的就是定义一个函数模板,让该函数模板将工作委托给类模板函数对象。然后,您可以将此类模板部分专门化为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

上的输出