После вопроса Как я могу определить, может ли тип передаваться в std::ostream? Я написал трейт класс, который говорит, может ли какой-либо тип передаваться в поток ввода-вывода. Черта, казалось, работала хорошо до тех пор, пока я не обнаружил проблему.
Я использую код внутри проекта, который использует LLVM, и я использую их класс StringRef (который по духу похож на предложенный std::string_view). 1StringRef.html" rel="nofollow noreferrer">Вот ссылка на документацию Doxygen для класса, откуда вы можете найдите файл заголовка объявления, если это необходимо. Поскольку LLVM не предоставляет оператора‹‹ для потоковой передачи объектов StringRef в стандартные потоки (они используют пользовательский облегченный класс потока), я написал его.
Однако, когда я использую трейт, он не работает, если мой пользовательский оператор‹‹ объявлен после трейта (это происходит потому, что у меня есть трейт в одном заголовке, а функция оператора — в другом). ). Раньше я думал, что поиск в экземплярах шаблонов работает с точки зрения точки создания экземпляров, поэтому я думал, что он должен работать. На самом деле, как вы можете видеть ниже, с другим классом и его пользовательским оператором‹‹, объявленным после типажа, все работает как положено (поэтому я обнаружил эту проблему только сейчас), поэтому я не могу понять, что делает StringRef особый.
Это полный пример:
#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;
}
Вопреки моим ожиданиям, это печатает:
false
true
Если я перемещаю объявление оператора‹‹ для StringRef перед объявлением типажа, оно печатает true. Итак, почему происходит эта странная вещь и как я могу решить эту проблему?