简体   繁体   English

如何std :: enable_if仅在特定模板具有给定类的专业化条件时

[英]How to std::enable_if only if a certain template has a specialization for a given class

I have the following template: 我有以下模板:

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);
}
}

which helps google-test display human-readable diagnostics when comparing hobbits: 在比较霍比特人时,这有助于Google测试显示人类可读的诊断信息:

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
}
}

The enable_if is there to prevent this templated operator<< from being applied to any old class (the naive version without enable_if is ambiguous for classes which already have streaming operators, eg std::string ). enable_if可以防止将此模板化的operator<<应用于任何旧类(没有enable_if的朴素版本对于已经具有流运算符的类是不明确的,例如std::string )。

However, if there is an enum which doesn't specialize enumclass , 但是,如果存在一个不专门枚举enumclass的枚举,

enum class Wizard { Gandalf, Radagast, Saruman };
const Wizard g = Wizard::Gandalf, s = Wizard::Saruman;

then the following fails to compile 那么以下内容无法编译

EXPECT_EQ(g, s);

with error: no type named 'helper' in 'aws::enumclass<Wizard>' because the compiler tries to apply the templated operator<< to Wizard. error: no type named 'helper' in 'aws::enumclass<Wizard>'因为编译器尝试将模板化的operator<<应用于向导。

Is it possible to construct an enable_if that would only apply this operator<< if there is a specialization of enumclass<Enum> ? 是否有可能构建一个enable_if将仅适用该运营商<<如果有一个专业化enumclass<Enum> Google-test then would fall back to display the raw bytes of Wizard and it would compile. 然后,Google-test将回退以显示Wizard的原始字节并进行编译。

Failing that, is it possible to construct an enable_if which would only allow types in a certain namespace (eg MiddleEarth)? 如果失败,是否可以构造一个enable_if ,它仅允许某个命名空间(例如MiddleEarth)中的类型? This would solve the problem if Wizard is not in the MiddleEarth namespace. 如果向导不在MiddleEarth命名空间中,则可以解决此问题。 All the enums in MiddleEarth are supposed to have a specialization for enumclass . MiddleEarth中的所有枚举都应该具有枚举类的enumclass

You can just move the helper_of substitution into the template specification itself: 您可以仅将helper_of替换项移动到模板规范本身中:

template <typename Enum,
          typename Helper = helper_of<Enum>>
std::ostream& operator<<(std::ostream& strm, Enum e)
{
    return strm << Helper::to_string(e);
}

That way, if the helper_of substitution fails (that is, enumclass isn't specialized for the given Enum ), the entire overload will be thrown out due to SFINAE rather than being a hard compile error - since now we're in the immediate context of the substitution itself. 这样,如果helper_of替换失败(即enumclass不适用于给定的Enum ),则整个重载将由于SFINAE而抛出,而不是硬编译错误-因为现在我们处于即时上下文中替代本身。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM