Gcc'de belirsiz operatör


13

Bazı stl kaplarını yazdırmak için bir işlev şablonu yaptım

#include <iostream>
#include <vector>
#include <string>

template <template <typename, typename> class C, typename T, typename A>
std::ostream& operator<<(std::ostream& os, const C<T, A>& container)
{ 
    for (auto& elem : container) 
    { 
        os << elem << " "; 
    } 

    return os; 
}

int main()
{
    std::vector<std::string> v { "One", "Two", "Three" };

    std::cout << v << std::endl;

    return 0;
}

Bu, MSVC, Clang ve ICC'de beklendiği gibi derlenir ve çalışır, ancak GCC (gövde) ile derlendiğinde operator<<hat için belirsiz bir hata verir os << elem << " ". Ve bu hata bile yalnızca bayrakla -std=c++17veya derleme sırasında görünür -std=c++2a.

std::stringDerleyici , varsayılan olarak , tür için varsayılan olarak operator<<bir çıkış akışını kabul eden global bir işlev şablonu ve bir derleyici algıladığından , hata makul görünmektedir .basic_string<CharT, Traits, Allocator>Allocatorstd::allocator

Benim sorum neden derleme ve diğer 3 derleyicileri ile çalışır, benim anlayışımdan, en azından Clang, linux üzerinde gcc ile aynı standart kütüphane uygulamasını kullanır, bu yüzden aynı işlev şablonu vardır operator<<

Bildirilen hata:

error: ambiguous overload for 'operator<<' (operand types are 'std::ostream' {aka 'std::basic_ostream<char>'} and 'const std::__cxx11::basic_string<char>')

Ve iki aday

note: candidate: 'std::ostream& operator<<(std::ostream&, const C<T, A>&) [with C = std::__cxx11::basic_string; T = char; A = std::char_traits<char>; std::ostream = std::basic_ostream<char>]'

note: candidate: 'std::basic_ostream<_CharT, _Traits>& std::operator<<(std::basic_ostream<_CharT, _Traits>&, const std::__cxx11::basic_string<_CharT, _Traits, _Allocator>&) [with _CharT = char; _Traits = std::char_traits<char>; _Alloc = std::allocator<char>]'

GCC, Clang ve ICC için derleyici argümanları

-std=c++2a -O3 -Wall -Wextra -Wpedantic -Werror

MSVC için bir

/std:c++latest /O2 /W3

Zorunlu godbolt bağlantısı: https://godbolt.org/z/R_aSKR

Yanıtlar:


8

std::stringDerleyici , varsayılan olarak , tür için varsayılan olarak operator<<bir çıkış akışını kabul eden global bir işlev şablonu ve bir derleyici algıladığından , hata makul görünmektedir .basic_string<CharT, Traits, Allocator>Allocatorstd::allocator

Gibi bir parametre eşleştirme avantajı C<T, A>gibi bir tipe basic_string<CharT, Traits, Allocator=std::allocator<CharT>>17 C ++ yenidir, bu gelir P0522 . Bu makaleden önce operatörünüz aday olarak kabul edilmez.

Ancak, clang bilerek bu özelliği varsayılan olarak uygulamamayı seçer. Gönderen statüleri :

Bir Hata Raporu'nun çözümü olmasına rağmen, bu özellik tüm dil sürümlerinde varsayılan olarak devre dışıdır ve -frelaxed-template-template-argsClang 4'ten sonraki bayrakla açıkça etkinleştirilebilir . Standartta yapılan değişiklik, şablon kısmi sıralaması için karşılık gelen bir değişiklikten yoksun ve makul ve daha önce geçerli olan kod için belirsizlik hatalarına neden oldu. Bu sorunun yakında çözülmesi bekleniyor.

Bu bayrağı eklediğinizde, kodunuzun clang'da da belirsizleştiğini görebilirsiniz. Örneğiniz, clang'ın burada karşı koruduğu makul ve önceden geçerli bir kod türüdür. Benzer bir örnek gördüm:

template <class T> struct some_trait;

template <template <class> class C, class A>
struct some_trait<C<A>> { /* ... */ };

template <template <class> class C, class A, class B>
struct some_trait<C<A, B>> { /* ... */ };

some_trait<vector<int>> eskiden (ikili sürümü kullanarak) iyiydi, ama şimdi belirsiz (ikili ve ikili sürüm arasında).

MSVC aynı seçimi yapabilir, ama bilmiyorum. Standartlara göre doğru cevap, çağrının belirsiz olmasıdır.

Sitemizi kullandığınızda şunları okuyup anladığınızı kabul etmiş olursunuz: Çerez Politikası ve Gizlilik Politikası.
Licensed under cc by-sa 3.0 with attribution required.