C++ 如何编写类型trait`is_container`或`is_vector`?
是否可以编写一个类型特征,其值对于所有常见STL结构(例如,C++ 如何编写类型trait`is_container`或`is_vector`?,c++,templates,sfinae,enable-if,C++,Templates,Sfinae,Enable If,是否可以编写一个类型特征,其值对于所有常见STL结构(例如,向量,集,映射,…)都为真 首先,我想写一个类型trait,对于向量为true,否则为false。我尝试过这个,但它无法编译: template<class T, typename Enable = void> struct is_vector { static bool const value = false; }; template<class T, class U> struct is_vector&
向量
,集
,映射
,…)都为真
首先,我想写一个类型trait,对于向量为true,否则为false。我尝试过这个,但它无法编译:
template<class T, typename Enable = void>
struct is_vector {
static bool const value = false;
};
template<class T, class U>
struct is_vector<T, typename boost::enable_if<boost::is_same<T, std::vector<U> > >::type> {
static bool const value = true;
};
模板
结构是向量{
静态布尔常量值=false;
};
模板
结构是向量{
静态布尔常量值=真;
};
错误消息是模板参数未在部分专门化中使用:U
你会说应该比那简单些
template <typename T, typename _ = void>
struct is_vector {
static const bool value = false;
};
template <typename T>
struct is_vector< T,
typename enable_if<
is_same<T,
std::vector< typename T::value_type,
typename T::allocator_type >
>::value
>::type
>
{
static const bool value = true;
};
模板
结构是_向量{
静态常量布尔值=假;
};
模板
结构是_向量::价值
>::类型
>
{
静态常量布尔值=真;
};
。。。但我不确定这是否更简单
在C++11中,可以使用类型别名(我认为,未经测试):
模板
使用is_vector=is_same>;
你的方法的问题是,类型U
在使用它的上下文中是不可推断的。事实上,经过一些尝试和错误后,我发现它非常简单:
template<class T>
struct is_vector<std::vector<T> > {
static bool const value = true;
};
模板
结构是向量{
静态布尔常量值=真;
};
我仍然想知道如何编写更通用的is\u容器
。我必须手动列出所有类型吗?模板
template <typename T>
struct is_container {
template <
typename U,
typename I = typename U::const_iterator
>
static int8_t test(U* u);
template <typename U>
static int16_t test(...);
enum { value = sizeof test <typename std::remove_cv<T>::type> (0) == 1 };
};
template<typename T, size_t N>
struct is_container <std::array<T,N>> : std::true_type { };
结构是一个容器{
模板<
类型名U,
typename I=typename U::const\U迭代器
>
静态int8_t试验(U*U);
模板
静态int16_t试验(…);
枚举{value=sizeof test(0)==1};
};
模板
结构是_容器:std::true_类型{};
虽然这里的其他答案试图猜测类是否是容器,但我想为您提供另一种选择,即命名要返回true的类型。您可以使用它来构建任意的is\uuuu(某物)
traits类型
template<class T> struct is_container : public std::false_type {};
template<class T, class Alloc>
struct is_container<std::vector<T, Alloc>> : public std::true_type {};
template<class K, class T, class Comp, class Alloc>
struct is_container<std::map<K, T, Comp, Alloc>> : public std::true_type {};
模板结构是_容器:public std::false_type{};
模板
结构是_容器:public std::true_type{};
模板
结构是_容器:public std::true_type{};
等等
您将需要包括
以及添加到规则中的任何类。为什么不为is\u容器执行类似操作
template <typename Container>
struct is_container : std::false_type { };
template <typename... Ts> struct is_container<std::list<Ts...> > : std::true_type { };
template <typename... Ts> struct is_container<std::vector<Ts...> > : std::true_type { };
// ...
模板
结构是_容器:std::false_类型{};
模板结构是_容器:std::true_类型{};
模板结构是_容器:std::true_类型{};
// ...
这样,用户可以通过部分专门化来添加自己的容器。至于is_vector等人,只需像我上面所做的那样使用部分专门化,但只限于一种容器类型,而不是多种容器。看,另一种基于SFINAE的检测类似STL容器的解决方案:
template<typename T, typename _ = void>
struct is_container : std::false_type {};
template<typename... Ts>
struct is_container_helper {};
template<typename T>
struct is_container<
T,
std::conditional_t<
false,
is_container_helper<
typename T::value_type,
typename T::size_type,
typename T::allocator_type,
typename T::iterator,
typename T::const_iterator,
decltype(std::declval<T>().size()),
decltype(std::declval<T>().begin()),
decltype(std::declval<T>().end()),
decltype(std::declval<T>().cbegin()),
decltype(std::declval<T>().cend())
>,
void
>
> : public std::true_type {};
模板
结构是_容器:std::false_类型{};
模板
结构是_容器_助手{};
模板
结构是一个容器<
T
std::有条件的<
假,,
是容器还是助手<
typename T::value\u type,
typename T::size\u type,
类型名T::分配器类型,
类型名T::迭代器,
类型名T::常量迭代器,
decltype(std::declval().size()),
decltype(std::declval().begin()),
decltype(std::declval().end()),
decltype(std::declval().cbegin()),
decltype(std::declval().cend())
>,
无效的
>
>:public std::true_type{};
当然,您可能会更改要检查的方法和类型
如果您只想检测STL容器(它意味着std::vector
,std::list
,等等),那么您应该这样做。在我们的项目中,我们仍然没有迁移到支持C++11的编译器,因此对于容器对象的类型特征,我必须编写一个简单的boost样式帮助程序:
template<typename Cont> struct is_std_container: boost::false_type {};
template<typename T, typename A>
struct is_std_container<std::vector<T,A> >: boost::true_type {};
template<typename T, typename A>
struct is_std_container<std::list<T,A> >: boost::true_type {};
template<typename T, typename A>
struct is_std_container<std::deque<T,A> >: boost::true_type {};
template<typename K, typename C, typename A>
struct is_std_container<std::set<K,C,A> >: boost::true_type {};
template<typename K, typename T, typename C, typename A>
struct is_std_container<std::map<K,T,C,A> >: boost::true_type {};
template<typename Cont> struct is_std_sequence: boost::false_type {};
template<typename T, typename A>
struct is_std_sequence<std::vector<T,A> >: boost::true_type {};
template<typename T, typename A>
struct is_std_sequence<std::list<T,A> >: boost::true_type {};
template<typename T, typename A>
struct is_std_sequence<std::deque<T,A> >: boost::true_type {};
模板结构是\u std\u容器:boost::false\u type{};
模板
struct是_std_容器:boost::true_type{};
模板
struct是_std_容器:boost::true_type{};
模板
struct是_std_容器:boost::true_type{};
模板
struct是_std_容器:boost::true_type{};
模板
struct是_std_容器:boost::true_type{};
模板结构是_std_序列:boost::false_type{};
模板
结构是_std_序列:boost::true_type{};
模板
结构是_std_序列:boost::true_type{};
模板
结构是_std_序列:boost::true_type{};
如果您还想使其适用于const std::vector,可以使用以下方法:
namespace local {
template<typename T, typename _ = void>
struct isVector: std::false_type {
};
template<typename T>
struct isVector<T,
typename std::enable_if<
std::is_same<typename std::decay<T>::type, std::vector<typename std::decay<T>::type::value_type, typename std::decay<T>::type::allocator_type> >::value>::type> : std::true_type {
};
}
TEST(TypeTraitTest, testIsVector) {
ASSERT_TRUE(local::isVector<std::vector<int>>::value);
ASSERT_TRUE(local::isVector<const std::vector<int>>::value);
ASSERT_FALSE(local::isVector<std::list<int>>::value);
ASSERT_FALSE(local::isVector<int>::value);
std::vector<uint8_t> output;
std::vector<uint8_t> &output2 = output;
EXPECT_TRUE(core::isVector<decltype(output)>::value);
EXPECT_TRUE(core::isVector<decltype(output2)>::value);
}
名称空间本地{
模板
结构isVector:std::false\u类型{
};
模板
struct isVector::type>:std::true\u type{
};
}
测试(TypeTrattest、testIsVector){
ASSERT_TRUE(local::isVector::value);
ASSERT_TRUE(local::isVector::value);
ASSERT_FALSE(local::isVector::value);
ASSERT_FALSE(local::isVector::value);
std::矢量输出;
标准::向量和输出2=输出;
EXPECT_TRUE(core::isVector::value);
EXPECT_TRUE(core::isVector::value);
}
如果没有std::remove\u cv调用,第二个ASSERT\u TRUE将失败。当然,这取决于你的需要。这里的问题是,根据规范,std::is_same检查const和volatile是否也匹配。我喜欢检测某个东西是否是容器的方法是查找数据()
和大小()
成员函数。像这样:
template <typename T, typename = void>
struct is_container : std::false_type {};
template <typename T>
struct is_container<T
, std::void_t<decltype(std::declval<T>().data())
, decltype(std::declval<T>().size())>> : std::true_type {};
模板
结构是_容器:std::false_类型{};
模板
结构是_容器:std::true_类型{};
快进到2018年和C++17,我非常大胆地改进@Frank answer
// clang++ prog.cc -Wall -Wextra -std=c++17
#include <iostream>
#include <vector>
namespace dbj {
template<class T>
struct is_vector {
using type = T ;
constexpr static bool value = false;
};
template<class T>
struct is_vector<std::vector<T>> {
using type = std::vector<T> ;
constexpr static bool value = true;
};
// and the two "olbigatory" aliases
template< typename T>
inline constexpr bool is_vector_v = is_vector<T>::value ;
template< typename T>
using is_vector_t = typename is_vector<T>::type ;
} // dbj
int main()
{
using namespace dbj;
std::cout << std::boolalpha;
std::cout << is_vector_v<std::vector<int>> << std::endl ;
std::cout << is_vector_v<int> << std::endl ;
} /* Created 2018 by dbj@dbj.org */
//clang++prog.cc-Wall-Wextra-std=c++17
#包括
#包括
名称空间dbj{
模板
结构是向量{
使用类型=T;
欺骗
// clang++ prog.cc -Wall -Wextra -std=c++17
#include <iostream>
#include <vector>
namespace dbj {
template<class T>
struct is_vector {
using type = T ;
constexpr static bool value = false;
};
template<class T>
struct is_vector<std::vector<T>> {
using type = std::vector<T> ;
constexpr static bool value = true;
};
// and the two "olbigatory" aliases
template< typename T>
inline constexpr bool is_vector_v = is_vector<T>::value ;
template< typename T>
using is_vector_t = typename is_vector<T>::type ;
} // dbj
int main()
{
using namespace dbj;
std::cout << std::boolalpha;
std::cout << is_vector_v<std::vector<int>> << std::endl ;
std::cout << is_vector_v<int> << std::endl ;
} /* Created 2018 by dbj@dbj.org */