区分结构与类型特征

时间:2015-05-28 17:53:46

标签: c++ templates c++11 typetraits

有没有办法区分struct哪个std::vector<T>与其他任何类型?

我有一些模板函数,如果T是一个包含std::vector<T>的结构,那么它应该是专用的,所以我正在寻找的是:

template<typename T> method(const T& object)
{
  static_assert(!contains_vector<T>::value, "This method must be specialized");
  // implementation
}

这样

struct Foo {
  uint32_t foo;
  float bar;
};

struct Bar {
  uint16_t foo;
  vector<float> bar;
}

contains_vector<float>::value == false;
contains_vector<Foo>::value == false;
contains_vector<Bar>::value == true;

我试图找出如何区分<type_traits>这种差异。

2 个答案:

答案 0 :(得分:2)

在一般情况下,没有。 C ++没有反射。因此,如果你想写一个类型特征“这个任意泛型结构包含一个vector的成员吗?”,这是不可能的。

但是,如果您控制了要测试的所有类型,则可以使用BOOST_FUSION_ADAPT_STRUCT对其进行检测,这会增加反射:

BOOST_FUSION_ADAPT_STRUCT(
    Foo,
    (uint32_t, foo)
    (float, bar)
)

BOOST_FUSION_ADAPT_STRUCT(
    Bar,
    (uint16_t, foo)
    (std::vector<float>, bar)
)

这会使您的结构FooBar的功能就像它们从一开始就是boost::fusion个序列一样。在那之后,写一个类型特征只涉及所有常见的Boost Fusion元编程hackery:

template <typename Seq>
struct contains_vector {
    // metafunction class for checking if a type is a std::vector<T,A>
    struct is_vector {
        template <typename T>
        struct apply : std::false_type { };

        template <typename T, typename A>
        struct apply<std::vector<T,A>> : std::true_type { };    
    };

    // think std::find_if()
    using iter = typename boost::fusion::result_of::find_if<Seq, is_vector>::type;
    // think .end()
    using end = typename boost::fusion::result_of::end<Seq>::type;

    // if iter == end, it's not found, so have to flip the sign
    using type = std::integral_constant<bool, !std::is_same<iter, end>::value>;
};

有了这个:

static_assert(contains_vector<Bar>::type::value, "");    // OK
static_assert(!contains_vector<Foo>::type::value, "");   // OK

请注意,我使用find_ifend而不是any,因为作为元函数的那个​​总是返回bool

答案 1 :(得分:0)

您应该考虑使用SFINAE(替换失败不是错误)

struct Foo {
  uint32_t foo;
  float bar;
};

struct Bar {
  typedef vector<float> bar_vector;
  uint16_t foo;
  bar_vector bar;
};

注意在struct Bar中添加了typedef。

template <typename T>
struct contains_vector {
    // Types "yes" and "no" are guaranteed to have different sizes,
    // specifically sizeof(yes) == 1 and sizeof(no) == 2.
    typedef char yes[1];
    typedef char no[2];

    template <typename C>
    static yes& test(typename C::bar_vector*);

    template <typename>
    static no& test(...);

    // If the "sizeof" of the result of calling test<T>(nullptr) is equal to sizeof(yes),
    // the first overload worked and T has a nested type named foobar.
    static const bool value = sizeof(test<T>(nullptr)) == sizeof(yes);
};

然后,您可以确定结构是否包含指示存在向量的typedef:

std::cout << contains_vector<int>::value << std::endl;
std::cout << contains_vector<Bar>::value << std::endl;
std::cout << contains_vector<Foo>::value << std::endl;

可以在C ++ 11中进行简化。