6

Przeprowadzamy migrację do Sun Studio 12.1 iz nowym kompilatorem [CC: Sun C++ 5.10 SunOS_sparc 2009/06/03]. Występuje błąd kompilacji podczas kompilowania kodu, który kompilował się dobrze z wcześniejszą wersją Sun Compiler [CC: Sun WorkShop 6 update 2 C++ 5.3 2001/05/15].Błąd kompilacji szablonu w Sun Studio 12

To jest błąd kompilacji, który dostaję.

"Sample.cc": Error: Could not find a match for LoopThrough(int[2]) needed in main(). 1 Error(s) detected. *** Error code 1.

KOD:

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

Gdybym odkomentowaniu kod z wersji Generic, kod kompiluje grzywny i generycznych wersji nazywa. Nie widzę tego problemu z MSVC 2010 z wyłączonymi rozszerzeniami i tym samym przypadkiem z ideonem here. Wywoływana jest wyspecjalizowana wersja funkcji. Teraz pytanie brzmi: czy jest to błąd w Kompilatorze Sun?

Jeśli tak, w jaki sposób możemy złożyć zgłoszenie błędu?

+1

Czy usunięcie const może workarodun to? – PlasmaHH

+0

Tak. Usunięcie const lub dodanie const do int arr [] to obejście. Ale chciałbym się dowiedzieć, czy to błąd w kompilatorze, czy też moje zrozumienie jest złe. – Jagannath

+2

Są szanse, że najnowsze wersje clangu, gcc, comeau i msvc się zgadzają, to jest błąd w SunCC. Zauważ też, że SunCC jest (nie) znany z tego, że jest zapluskwiony. Co prowadzi do pytania: dlaczego nie używać gcc? – PlasmaHH

Odpowiedz

2

kompilator nie podąża za standard w tym przypadku i buggy. Przyjrzyjmy się odpowiednim sekcjom.

Pierwszy z 13,3/3 mamy:

...

— First, a subset of the candidate functions—those that have the proper number of arguments and meet certain other conditions—is selected to form a set of viable functions (13.3.2).

— Then the best viable function is selected based on the implicit conversion sequences (13.3.3.1) needed to match each argument to the corresponding parameter of each viable function.

Więc obie funkcje mają taką samą liczbę argumentów i są uważane za kandydatów. Teraz musimy znaleźć najlepszą realną funkcję w

13.3.3:

let ICSi(F) denote the implicit conversion sequence that converts the ith argument in the list to the type of the ith parameter of viable function F. 13.3.3.1 defines the implicit conversion sequences and 13.3.3.2 defines what it means for one implicit conversion sequence to be a better conversion sequence or worse conversion sequence than another

Następnie mamy

Given these definitions, a viable function F1 is defined to be a better function than another viable function F2 if for all arguments i, ICSi(F1) is not a worse conversion sequence than ICSi(F2), and then

— for some argument j, ICSj(F1) is a better conversion sequence than ICSj(F2), or, if not that,

— F1 is a nontemplate function and F2 is a template function specialization, or, if not that,

— F1 and F2 are template functions, and the function template for F1 is more specialized than the template for F2 according to the partial ordering rules described in 14.5.5.2, or, if not that,

Obie funkcje są równe dla pierwszej reguły (dodawanie const) a druga reguła nie ma zastosowania (oba są szablonami). Przechodzimy więc do trzeciej reguły. Od wersji 14.5.5.2 (którą zacytuję na żądanie) dowiadujemy się, że wersja const int jest bardziej wyspecjalizowana niż wersja const Item, a więc najlepiej pasuje przeciążenie const int, które powinno następnie zostać wywołane.

Najlepszym tymczasowym rozwiązaniem jest prawdopodobnie drugą przeciążenie:

template<size_t SZ> 
void LoopThrough(int (&Item)[SZ]) 
{ 
    LoopThrough(static_cast<const int (&)[SZ]>(Item)); 
} 
1

Twój kompilator jest błędny. Oba przeciążenia mają wyprowadzone argumenty z szablonów, a rozdzielczość przeciążania powinna wybrać najbardziej wyspecjalizowaną. Czy oprócz uzyskania nowego kompilatora, co możesz zrobić?

Po pierwsze, warto sobie uświadomić, że - nawet przy zgodnych kompilatorach - generalnie nie jest dobrym pomysłem na przeciążenie różnych szablonów funkcji. Zobacz np. Artykuł 66 z C++ Coding Standards: 101 Rules, Guidelines, and Best Practices autorstwa Herb Sutter i Andrei Alexandrescu.

Na szczęście ten przedmiot sugeruje również możliwą poprawkę. Wszystko, co musisz zrobić, to zdefiniować szablon jednej funkcji i pozwolić temu szablonowi funkcji przekazać pracę do obiektu funkcji szablonu klasy. Następnie możesz częściowo specjalizować ten szablon klasy dla 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);  
    } 
} 

Najprawdopodobniej kompilator zainicjuje połączenie z obiektem funkcji i całkowicie zoptymalizuje tymczasowy. Mam nadzieję, że twój kompilator będzie miał również poprawnie zaimplementowaną częściową specjalizację szablonów klas.

Wyjście na Ideone

+0

Problem OP polega w szczególności na tym, że tylko z jednym szablonem nie można go skompilować, ponieważ kompilator nie będzie wiązał tablicy stałej z parametrem tablicy stałej. –

+0

@MarkB Bez względu na to, po prostu dobrym stylem jest dodatkowe ukierunkowanie na wyspecjalizowane obiekty funkcyjne zamiast przeciążeń wielu funkcji. – TemplateRex

Powiązane problemy