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

时间:2014-01-06 02:28:22

标签: c++ c++11 stl sfinae

我使用this魔法标题来获得轻松序列化STL容器的功能。

但是,我现在已经为我的类型转移了更多花哨的HTML序列化程序,我想要做的部分是将operator <<功能概括为我支持的新类型ohtmlstringstreamstringstream

以下是我(尝试)尝试执行此操作(ohtmlstringstream::write是一个公共模板方法,将其arg传递给私有成员stringstream的{​​{1}}):

operator<<

我遇到的第一个问题是,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::string时,它被视为一个容器,这是我不想要的东西;我想将字符串视为字符串,而不是容器。当然,就ohtmlstringstream而言,std :: string肯定是chars的容器。

这是摘自pretty_print

prettyprint.hpp

这里的问题是我不清楚我如何使用SFINAE和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> 以及其他这些东西来构建另一个谓词,对所有容器评估为真,除了 enable_if

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

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

确实,使用模板枚举所有STL容器可以解决这两个问题。我想我会开始这样做。但我仍然想知道原始第一个问题的答案。如何使用std::vector排除特定类型?

1 个答案:

答案 0 :(得分:0)

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

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

如果您想要重用一个特征,只需创建一个继承std::integral_constant<bool,逻辑的>{};

如果您有完整的C ++ 11支持,请尝试编写constexpr函数,类型为T并返回true而不是traits类。在C ++ 1y中,当概念lite到达时,这可能很有用。