Operatore ambiguo in gcc


13

Ho creato un modello di funzione per stampare alcuni dei contenitori stl

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

Questo compila e funziona come previsto su MSVC, Clang e ICC, ma durante la compilazione con GCC (trunk) genera un operator<<errore ambiguo per la linea os << elem << " ". E anche questo errore appare solo durante la compilazione con il flag -std=c++17o -std=c++2a.

L'errore sembra ragionevole, poiché std::string, poiché il compilatore rileva un modello di funzione esistente che per globale operator<<che accetta un flusso di output e un basic_string<CharT, Traits, Allocator>, con il Allocatortipo predefinito std::allocator.

La mia domanda sarebbe perché si compila e funziona con gli altri 3 compilatori, almeno dalla mia comprensione, Clang, usa la stessa implementazione di libreria standard su Linux di gcc, quindi ha lo stesso modello di funzione per il operator<<

L'errore segnalato è

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

E i due candidati

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>]'

Argomenti del compilatore per GCC, Clang e ICC

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

Un per MSVC

/std:c++latest /O2 /W3

Link godbolt obbligatorio: https://godbolt.org/z/R_aSKR

Risposte:


8

L'errore sembra ragionevole, poiché std::string, poiché il compilatore rileva un modello di funzione esistente che per globale operator<<che accetta un flusso di output e un basic_string<CharT, Traits, Allocator>, con il Allocatortipo predefinito std::allocator.

Questa capacità di abbinare un parametro simile C<T, A>a un tipo come basic_string<CharT, Traits, Allocator=std::allocator<CharT>>è nuova in C ++ 17, proviene da P0522 . Prima di quel documento, il tuo operatore non sarebbe stato considerato un candidato.

Tuttavia, clang sceglie intenzionalmente di non implementare questa funzione per impostazione predefinita. Dal loro stato :

Nonostante sia la risoluzione di un rapporto sui difetti, questa funzione è disabilitata per impostazione predefinita in tutte le versioni linguistiche e può essere abilitata esplicitamente con il flag da -frelaxed-template-template-argsClang 4 in poi. La modifica allo standard manca di una corrispondente modifica per l'ordinamento parziale del modello, con conseguenti errori di ambiguità per codice ragionevole e precedentemente valido. Questo problema dovrebbe essere presto risolto.

Puoi vedere che quando aggiungi quel flag, il tuo codice diventa ambiguo anche su clang. Il tuo esempio è il tipo di codice ragionevole e precedentemente valido contro il quale clang protegge da qui. Un tipo simile di esempio che ho visto:

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>> andava bene (usando la versione binaria), ma ora diventa ambiguo (tra la versione unaria e quella binaria).

MSVC potrebbe fare la stessa scelta, ma non lo so. La risposta corretta per lo standard è che la chiamata è ambigua.

Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.