detecting typedef at compile time (template metaprogramming)

≯℡__Kan透↙ 提交于 2019-11-28 20:47:04
iammilind

If you simply want if a given type contains const_iterator then following is a simplified version of your code:

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(){ ... }
};

See this answer for some explanation of how this technique works.

You can create a trait has_const_iterator that provides a boolean value and use that in the specialization.

Something like this might do it:

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 };
};

And then you can specialize like this:

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}
};

Here's another version of a member type trait check:

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);
};
Paul Fultz II

There is a couple of ways to do this. In C++03, you could use boost and enable_if to define the trait (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(){ ... }
};

In C++11, you could use Tick like this:

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(){ ... }
};

Also with Tick you can further enhance the trait to actually detect that the const_iterator is actually an iterator, as well. So say we define a simple is_iterator trait like this:

TICK_TRAIT(is_iterator,
    std::is_copy_constructible<_>)
{
    template<class I>
    auto require(I&& i) -> valid<
        decltype(*i),
        decltype(++i)
    >;
};

We can then define has_const_iterator trait to check that the const_iterator type matches the is_iterator trait like this:

TICK_TRAIT(has_const_iterator)
{
    template<class T>
    auto require(const T&) -> valid<
        has_type<typename T::const_iterator, is_iterator<_>>
    >;
};
易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!