Dopo la domanda How can I detect if a type can be streamed to an std::ostream? Ho scritto una classe di caratteri che dice se alcuni tipi possono essere trasmessi in streaming a un flusso IO. Il tratto ha funzionato bene fino ad ora che ho scoperto un problema.Perché il mio operatore di ricerca della classe dei modelli dei tratti non è << per llvm :: StringRef?
Sto usando il codice all'interno di un progetto che utilizza LLVM e sto usando la loro classe StringRef (che è simile nello spirito alla proposta std :: string_view). Here è un collegamento al doc Doxygen per la classe, da cui è possibile trovare il suo file di intestazione della dichiarazione, se necessario. Dal momento che LLVM non fornisce un operatore < < per lo streaming di oggetti StringRef ai flussi std (utilizzano una classe di flusso leggero personalizzata), ne ho scritto uno.
Tuttavia, quando uso il tratto non funziona se il mio operatore personalizzato < < è dichiarato dopo il tratto (questo accade perché ho il tratto in un colpo di testa e l'operatore < < funzione in un altro) . Ero solito pensare che la ricerca nelle istanze dei template funzionasse dal punto di vista del punto di istanziazione, quindi ho pensato che avrebbe dovuto funzionare. In realtà, come puoi vedere qui sotto, con un'altra classe e il suo operatore personalizzato < <, dichiarato dopo il tratto, tutto funziona come previsto (ecco perché ho scoperto questo problema solo ora), quindi non riesco a capire cosa rende StringRef speciale.
Questo è l'esempio completo:
#include <iostream>
#include "llvm/ADT/StringRef.h"
// Trait class exactly from the cited question's accepted answer
template<typename T>
class is_streamable
{
template<typename SS, typename TT>
static auto test(int)
-> decltype(std::declval<SS&>() << std::declval<TT>(),
std::true_type());
template<typename, typename>
static auto test(...) -> std::false_type;
public:
static const bool value = decltype(test<std::ostream,T>(0))::value;
};
// Custom stream operator for StringRef, declared after the trait
inline std::ostream &operator<<(std::ostream &s, llvm::StringRef const&str) {
return s << str.str();
}
// Another example class
class Foo { };
// Same stream operator declared after the trait
inline std::ostream &operator<<(std::ostream &s, Foo const&) {
return s << "LoL\n";
}
int main()
{
std::cout << std::boolalpha << is_streamable<llvm::StringRef>::value << "\n";
std::cout << std::boolalpha << is_streamable<Foo>::value << "\n";
return 0;
}
Contrariamente alle mie aspettative, questo stampe:
false
true
Se sposto la dichiarazione dell'operatore < < per stringRef prima della dichiarazione trait , stampa vero. Quindi perché sta succedendo questa cosa strana e come posso risolvere questo problema?
Metti la tua operatore nello stesso spazio dei nomi come il tipo per consentire ADL. – Yakk
@Yakk Questa è la risposta, quindi perché non scriverne una? – jrok
@jrok perché sto facendo addormentare un bambino per un pisolino, e questo non è facile da controllare è il vero problema e l'elaborazione ecc. :) – Yakk