我有以下模板:
namespace std {
template<typename Enum>
typename std::enable_if<std::is_enum<Enum>::value, std::ostream&>::type
operator<<(std::ostream& strm, Enum e)
{
return strm << helper_of<Enum>::to_string(e);
}
}
有助于谷歌测试在比较霍比特人时显示人类可读的诊断信息:
template <typename T> struct enumclass {}; // generic template
template <typename T>
using helper_of = typename enumclass<T>::helper; // more mnemonic
namespace MiddleEarth {
enum class Hobbit { Bilbo, Frodo, Sam };
struct HobbitHelper{
std::string to_string(Hobbit H);
Hobbit from_string(std::string const& s); // Hobbit-forming
};
template <> struct enumclass<Hobbit> {
using helper = HobbitHelper; // links Hobbit to its helper
}
}
enable_if
是为了防止这个模板operator<<
被应用于任何旧类(没有enable_if的朴素版本对于已经有流操作符的类来说是不明确的,例如std::string
)
但是,如果有一个不专门化enumclass
的枚举,
enum class Wizard { Gandalf, Radagast, Saruman };
const Wizard g = Wizard::Gandalf, s = Wizard::Saruman;
然后以下无法编译
EXPECT_EQ(g, s);
带有error: no type named 'helper' in 'aws::enumclass<Wizard>'
的因为编译器尝试将模板operator<<
应用于向导。
是否可以构建仅应用此运算符的enable_if
&lt;&lt;如果有enumclass<Enum>
的专业化?然后谷歌测试将回退显示向导的原始字节,它将编译。
如果失败了,是否可以构造一个只允许某个命名空间中类型的enable_if
(例如MiddleEarth)?如果Wizard不在MiddleEarth命名空间中,这将解决问题。 MiddleEarth中的所有枚举都应该具有enumclass
的专业化。
答案 0 :(得分:5)
您可以将helper_of
替换移动到模板规范本身:
template <typename Enum,
typename Helper = helper_of<Enum>>
std::ostream& operator<<(std::ostream& strm, Enum e)
{
return strm << Helper::to_string(e);
}
这样,如果helper_of
替换失败(即enumclass
不是专门用于给定的Enum
),整个重载将因SFINAE而不是SFINAE而被抛弃是一个硬编译错误 - 因为现在我们在替换本身的直接上下文中。