如何 std::enable_if 仅当某个模板具有给定 class 的专业化时
How to std::enable_if only if a certain template has a specialization for a given class
我有以下模板:
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);
}
}
这有助于 google-test 在比较霍比特人时显示人类可读的诊断信息:
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<<
被应用到任何旧的 class (没有 enable_if 的原始版本对于 classes 已经有流媒体运营商,例如 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
仅在有 enumclass<Enum>
的特化时才应用此运算符<<? Google-test 然后会返回显示 Wizard 的原始字节并编译。
如果做不到这一点,是否可以构建一个 enable_if
只允许特定命名空间(例如 MiddleEarth)中的类型?如果 Wizard 不在 MiddleEarth 命名空间中,这将解决问题。 MiddleEarth 中的所有枚举都应该具有 enumclass
.
的特化
您可以将 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 而被抛出而不是硬编译错误 - 因为现在我们处于替换本身的直接上下文中。
我有以下模板:
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);
}
}
这有助于 google-test 在比较霍比特人时显示人类可读的诊断信息:
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<<
被应用到任何旧的 class (没有 enable_if 的原始版本对于 classes 已经有流媒体运营商,例如 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
仅在有 enumclass<Enum>
的特化时才应用此运算符<<? Google-test 然后会返回显示 Wizard 的原始字节并编译。
如果做不到这一点,是否可以构建一个 enable_if
只允许特定命名空间(例如 MiddleEarth)中的类型?如果 Wizard 不在 MiddleEarth 命名空间中,这将解决问题。 MiddleEarth 中的所有枚举都应该具有 enumclass
.
您可以将 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 而被抛出而不是硬编译错误 - 因为现在我们处于替换本身的直接上下文中。