我目前正在做一些模板元编程。在我的情况下,我可以处理任何“可迭代”类型,即typedef foo const_iterator
以相同方式存在的任何类型。我试图使用新的C ++ 11模板元编程,但是我找不到一种方法来检测是否缺少某种类型。
因为我还需要根据其他特征打开/关闭其他模板专精,我目前正在使用带有两个参数的模板,第二个通过std::enable_if
生成。以下是我目前正在做的事情:
template <typename T, typename Enable = void>
struct Foo{}; // default case is invalid
template <typename T>
struct Foo< T, typename std::enable_if<std::is_fundamental<T>::value>::type>{
void do_stuff(){ ... }
};
template<typename T>
struct exists{
static const bool value = true;
};
template<typename T>
struct Foo<T, typename std::enable_if<exists< typename T::const_iterator >::value >::type> {
void do_stuff(){ ... }
};
如果没有exists
助手模板,我无法做到这一点。例如,简单地做
template<typename T>
struct Foo<T, typename T::const_iterator> {
void do_stuff(){ ... }
};
不起作用,因为在应该使用此专门化的情况下,实例化了无效的默认情况。
但是我在新的C ++ 11标准中找不到这个exists
,据我所知,这个标准只是从boost::type_traits
中获取这种东西。但是,boost::type_traits
{{1}}并未显示任何可以替代使用的内容。
是否缺少此功能,还是我忽略了其他一些明显的方法来实现所需的行为?
答案 0 :(得分:14)
如果您只是想要一个给定的类型包含const_iterator
,那么以下是您的代码的简化版本:
template<typename T>
struct void_ { typedef void type; };
template<typename T, typename = void>
struct Foo {};
template<typename T>
struct Foo <T, typename void_<typename T::const_iterator>::type> {
void do_stuff(){ ... }
};
有关此技术如何运作的一些解释,请参阅this answer。
答案 1 :(得分:7)
您可以创建一个提供布尔值的特征has_const_iterator
,并在特化中使用它。
这样的事可能会这样做:
template <typename T>
struct has_const_iterator {
private:
template <typename T1>
static typename T1::const_iterator test(int);
template <typename>
static void test(...);
public:
enum { value = !std::is_void<decltype(test<T>(0))>::value };
};
然后你可以像这样专注:
template <typename T,
bool IsFundamental = std::is_fundamental<T>::value,
bool HasConstIterator = has_const_iterator<T>::value>
struct Foo; // default case is invalid, so no definition!
template <typename T>
struct Foo< T, true, false>{
void do_stuff(){// bla }
};
template<typename T>
struct Foo<T, false, true> {
void do_stuff(){//bla}
};
答案 2 :(得分:4)
这是成员类型特征检查的另一个版本:
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);
};
答案 3 :(得分:1)
有几种方法可以做到这一点。在C ++ 03中,您可以使用boost和enable_if
来定义特征(docs,source):
BOOST_MPL_HAS_XXX_TRAIT_DEF(const_iterator);
template <typename T, typename Enable = void>
struct Foo;
template <typename T>
struct Foo< T, typename boost::enable_if<boost::is_fundamental<T> >::type>{
void do_stuff(){ ... }
};
template<typename T>
struct Foo<T, typename boost::enable_if<has_const_iterator<T> >::type> {
void do_stuff(){ ... }
};
在C ++ 11中,您可以像这样使用Tick:
TICK_TRAIT(has_const_iterator)
{
template<class T>
auto require(const T&) -> valid<
has_type<typename T::const_iterator>
>;
};
template <typename T, typename Enable = void>
struct Foo;
template <typename T>
struct Foo< T, TICK_CLASS_REQUIRES(std::is_fundamental<T>::value)>{
void do_stuff(){ ... }
};
template<typename T>
struct Foo<T, TICK_CLASS_REQUIRES(has_const_iterator<T>())> {
void do_stuff(){ ... }
};
同样使用Tick,您可以进一步增强特性,以实际检测到const_iterator
实际上也是一个迭代器。所以说我们定义一个简单的is_iterator
特征:
TICK_TRAIT(is_iterator,
std::is_copy_constructible<_>)
{
template<class I>
auto require(I&& i) -> valid<
decltype(*i),
decltype(++i)
>;
};
然后,我们可以定义has_const_iterator
特征来检查const_iterator
类型是否与is_iterator
特征匹配:
TICK_TRAIT(has_const_iterator)
{
template<class T>
auto require(const T&) -> valid<
has_type<typename T::const_iterator, is_iterator<_>>
>;
};