遵循问题如何检测类型是否可以流式传输到 std::ostream?我编写了一个特征类,说明是否可以将某种类型流式传输到 IO 流。直到现在我发现了一个问题,这个特性似乎运作良好。
我在使用 LLVM 的项目中使用代码,并且正在使用他们的 StringRef 类(在精神上与建议的 std::string_view 相似)。这是该类的 Doxygen 文档的链接,如果需要,您可以从中找到它的声明头文件。由于 LLVM 没有提供 operator<< 来将 StringRef 对象流式传输到 std 流(它们使用自定义的轻量级流类),因此我编写了一个。
但是,当我使用 trait 时,如果我的自定义 operator<< 在 trait之后声明,它就不起作用(发生这种情况是因为我在一个标题中具有 trait,而在另一个标题中具有 operator<< 函数)。我曾经认为模板实例化中的查找从实例化点的角度来看是有效的,所以我认为它应该有效。实际上,正如您在下面看到的那样,使用另一个类及其自定义运算符<<,在特征之后声明,一切都按预期工作(这就是我现在才发现这个问题的原因),所以我不知道是什么让 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 的 operator<<的声明,它会打印为 true。那么为什么会发生这种奇怪的事情,我该如何解决这个问题呢?