【问题标题】:How to std::enable_if only if a certain template has a specialization for a given class仅当某个模板具有给定类的特化时如何 std::enable_if
【发布时间】:2015-08-17 15:12:17
【问题描述】:

我有以下模板:

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&lt;&lt; 应用于任何旧类(没有 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&lt;Wizard&gt;',因为编译器会尝试将模板化的operator&lt;&lt; 应用于Wizard。

如果有 enumclass&lt;Enum&gt; 的特化,是否可以构造一个仅应用此运算符enable_if ?然后,Google-test 将回退以显示 Wizard 的原始字节并进行编译。

如果做不到这一点,是否可以构造一个enable_if,它只允许某个命名空间中的类型(例如 MiddleEarth)?如果 Wizard 不在 MiddleEarth 命名空间中,这将解决问题。 MiddleEarth 中的所有枚举都应该具有enumclass 的特化。

【问题讨论】:

    标签: c++ templates c++11 enable-if


    【解决方案1】:

    您可以将 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 而被抛出,而不是硬编译错误 -因为现在我们处于替换本身的直接上下文中。

    【讨论】:

    • 美丽。即使根本不使用Helper,它也可以工作(即return 语句是原始的return strm &lt;&lt; helper_of&lt;Enum&gt;::to_string(e);(再次应用了helper_of,冗余)。
    猜你喜欢
    • 2019-08-30
    • 1970-01-01
    • 2012-04-05
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多