区分具有类型特征的结构体

Distinguishing structs with type traits

本文关键字:特征 结构体 类型      更新时间:2023-10-16

是否有办法将具有std::vector<T>struct与任何其他类型区分开来?

我有一些模板函数,如果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>来区分这种差异。

一般情况下,没有。c++没有反射。所以,如果你想写一个类型trait"这个任意的泛型结构是否包含一个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序列一样起作用。之后,编写类型trait只涉及所有常见的Boost Fusion元编程技巧:

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

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

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

注意在struct Bar中增加了typepedef。

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

然后可以确定该结构体是否包含指示存在vector的类型定义:

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中简化