首页
学习
活动
专区
圈层
工具
发布
社区首页 >问答首页 >扩展enable_if类型以排除匹配类型

扩展enable_if类型以排除匹配类型
EN

Stack Overflow用户
提问于 2014-01-06 02:28:21
回答 1查看 1K关注 0票数 0

我正在使用this神奇的标题来获得轻松序列化STL容器的能力。

然而,我现在已经转到了更加花哨的HTML序列化器中,我想要做的部分工作是将operator <<功能推广到由stringstream支持的新类型ohtmlstringstream中。

下面是我(功能)尝试这样做的尝试(ohtmlstringstream::write是一个公共模板方法,它将其arg传递给私有成员stringstreamoperator<<):

代码语言:javascript
复制
namespace std {
    template<typename T>
    inline typename enable_if< ::pretty_print::is_container<T>::value, ohtmlstringstream&>::type
    operator<<(ohtmlstringstream& os, const T& container) {
        auto it = std::begin(container);
        const auto the_end = end(container);
        os.write("<div class='container'>");
        while(it != the_end) {
            os << *it;
            it++;
        }
        os.write("</div>");
        return os;
    }
}

我遇到的第一个问题是,每当std::stringohtmlstringstream上使用时,它都被视为容器,这是我不想要的;我想把字符串看作只是字符串,而不是容器。当然,就pretty_print而言,std::string无疑是一个字符容器。

这是prettyprint.hpp的摘录:

代码语言:javascript
复制
namespace pretty_print
{

    // SFINAE type trait to detect whether T::const_iterator exists.

    template<typename T>
    struct has_const_iterator
    {
    private:
        typedef char                      yes;
        typedef struct { char array[2]; } no;

        template <typename C> static yes test(typename C::const_iterator*);
        template <typename C> static no  test(...);
    public:
        static const bool value = sizeof(test<T>(0)) == sizeof(yes);
        typedef T type;
    };

    // SFINAE type trait to detect whether "T::const_iterator T::begin/end() const" exist.

    template <typename T>
    struct has_begin_end_OLD
    {
        struct Dummy { typedef void const_iterator; };
        typedef typename std::conditional<has_const_iterator<T>::value, T, Dummy>::type TType;
        typedef typename TType::const_iterator iter;

        struct Fallback { iter begin() const; iter end() const; };
        struct Derived : TType, Fallback { };

        template<typename C, C> struct ChT;

        template<typename C> static char (&f(ChT<iter (Fallback::*)() const, &C::begin>*))[1];
        template<typename C> static char (&f(...))[2];
        template<typename C> static char (&g(ChT<iter (Fallback::*)() const, &C::end>*))[1];
        template<typename C> static char (&g(...))[2];

        static bool const beg_value = sizeof(f<Derived>(0)) == 2;
        static bool const end_value = sizeof(g<Derived>(0)) == 2;
    };

    template <typename T>
    struct has_begin_end
    {
        template<typename C> static char (&f(typename std::enable_if<
                                             std::is_same<decltype(static_cast<typename C::const_iterator (C::*)() const>(&C::begin)),
                                             typename C::const_iterator(C::*)() const>::value, void>::type*))[1];

        template<typename C> static char (&f(...))[2];

        template<typename C> static char (&g(typename std::enable_if<
                                             std::is_same<decltype(static_cast<typename C::const_iterator (C::*)() const>(&C::end)),
                                             typename C::const_iterator(C::*)() const>::value, void>::type*))[1];

        template<typename C> static char (&g(...))[2];

        static bool const beg_value = sizeof(f<T>(0)) == 1;
        static bool const end_value = sizeof(g<T>(0)) == 1;
    };

    // Basic is_container template; specialize to derive from std::true_type for all desired container types

    template<typename T> struct is_container : public ::std::integral_constant<bool,
    has_const_iterator<T>::value && has_begin_end<T>::beg_value && has_begin_end<T>::end_value> { };

    template<typename T, std::size_t N> struct is_container<T[N]> : public ::std::true_type { };

    template<std::size_t N> struct is_container<char[N]> : public ::std::false_type { };

    template <typename T> struct is_container< ::std::valarray<T>> : public ::std::true_type { }; 

...<snip>

这里的问题是,我还不清楚如何使用SFINAE和enable_if以及其他这些东西来构建另一个谓词,该谓词对除std::string之外的所有容器都是真的。

这只是第一个问题。第二个问题是我的第一个代码清单中的行是os.write("<div class='container'>");。请注意,这是多么令人讨厌的不具体。我非常希望容器的序列化例程报告容器的实际类型(无论是std::mapstd::forward-list还是std::vector)。

我想知道的是,是否存在一些(相当合理的)方法来使用模板来实现这一点,或者我是否真的应该使用宏来显式地定义一系列模板,一个用于每个STL容器类型:这样,我就可以轻松地为任何给定的容器构建我想要的HTML类型。

确实,使用模板枚举所有STL容器将解决这两个问题。我想我会开始这么做的。但我还是想知道第一个问题的答案。如何使用enable_if排除特定类型

EN

回答 1

Stack Overflow用户

回答已采纳

发布于 2014-01-06 03:01:17

&&!std::is_same<Foo, std::string>::value添加到enable_if测试中。

enable_if<条件,可选类型>::type的语法可能会有所帮助--条件是任何编译时bool。你可以把更多的东西扔进去!

如果您想要重用一个特性,只需创建一个继承自std::integral_constant<bool,逻辑的特性( >{}; )即可。

如果您有完全的C++11支持,请尝试编写一个以T类型表示的constexpr函数,并返回true而不是属性类。在C++1y中,当概念lite出现时,这可能是有用的。

票数 0
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/20941971

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档