12

我目前正在做一些模板元编程。就我而言,我可以处理任何“可迭代”类型,即 atypedef 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这种东西中获取的。但是,在主页上forboost::type_traits没有显示对任何可以替代使用的任何内容的引用。

是否缺少此功能,或者我是否忽略了其他一些明显的方法来实现所需的行为?

4

4 回答 4

15

如果您只是想要给定类型是否包含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(){ ... }
};

有关此技术如何工作的一些解释,请参阅此答案。

于 2011-10-20T11:12:29.243 回答
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}
};
于 2011-10-20T10:35:26.103 回答
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);
};
于 2011-10-20T10:59:31.843 回答
2

有几种方法可以做到这一点。在 C++03 中,您可以使用 boost 并enable_if定义特征(docssource):

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_iteratortrait 来检查const_iterator类型是否与is_iteratortrait 匹配,如下所示:

TICK_TRAIT(has_const_iterator)
{
    template<class T>
    auto require(const T&) -> valid<
        has_type<typename T::const_iterator, is_iterator<_>>
    >;
};
于 2014-07-01T23:11:04.687 回答