我使用this魔法标题来获得轻松序列化STL容器的功能。
但是,我现在已经为我的类型转移了更多花哨的HTML序列化程序,我想要做的部分是将operator <<
功能概括为我支持的新类型ohtmlstringstream
由stringstream
。
以下是我(尝试)尝试执行此操作(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
排除特定类型?
答案 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到达时,这可能很有用。