如何编写类型特征“is_container”或“is_vector”
How to write a type trait `is_container` or `is_vector`?
是否可以为所有常见的STL结构(例如,vector
、set
、map
…)编写一个值为true的类型特征?
首先,我想写一个类型trait,对于vector
为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;
};
错误消息为template parameters not used in partial specialization: U
。
Look,另一个基于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 {};
当然,您可以更改要检查的方法和类型。
如果您只想检测STL容器(意味着std::vector
、std::list
等),您应该这样做。
更新。正如@Deduplitor所指出的,容器可能不符合AllocatorAwareContainer的要求(例如:std::array<T, N>
)。这就是为什么不需要检查T::allocator_type
的原因。但您可以以类似的方式检查任何/所有容器要求。
你会说它应该比这更简单。。。
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中,您可以使用类型别名(我认为,未经测试):
template <typename T>
using is_vector = is_same<T, std::vector< typename T::value_type,
typename T::allocator_type > >;
您的方法的问题在于,类型U
在使用它的上下文中是不可推导的。
事实上,经过一些尝试和错误,我发现它很简单:
template<class T>
struct is_vector<std::vector<T> > {
static bool const value = true;
};
我仍然想知道如何编写一个更通用的is_container
。我必须手工列出所有类型吗?
为什么不为is_container做这样的操作?
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 { };
// ...
这样,用户可以通过部分专业化来添加自己的容器。至于is_vector等人,只需像我上面所做的那样使用部分专门化,但将其限制为仅一种容器类型,而不是多个。
虽然这里试图猜测类是否是容器的其他答案可能适用于您,但我想为您提供一种选择,即命名要返回true的类型。您可以使用它来构建任意的is_(something)
特征类型。
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 {};
等等。
您需要包括<type_traits>
和您添加到规则中的任何类。
我喜欢检测某个东西是否是容器的方法是查找data()
和size()
成员函数。像这样:
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 {};
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 { };
快进到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 */
"布丁的证明"。有更好的方法可以做到这一点,但这适用于std::vector
。
我们还可以使用概念。我用GCC 10.1标志-std=c++20
编译了这个。
#include<concepts>
template<typename T>
concept is_container = requires (T a)
{
a.begin();
// Uncomment both lines for vectors only
// a.data(); // arrays and vectors
// a.reserve(1); // narrowed down to vectors
};
在我们的项目中,我们仍然没有成功迁移到支持C++11的编译器,所以对于容器对象的type_traits,我不得不编写一个简单的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 {};
如果您还想使其适用于conststd::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);
}
如果没有std::remove_cv调用,第二个ASSERT_TRUE将失败。当然,这取决于你的需要。这里的问题是,根据规范,std::is_same检查const和volatile是否也匹配。
- 有关插入适配器的错误。[错误]请求从 'back_insert_iterator<vector<>>' 类型转换为非标量类型
- 在c++中用vector填充一个简单的动态数组
- vector.resize()中的分配错误
- 使用std::vector的OpenCL矩阵乘法
- POCO::PostgreSQL:如何将std::vector支持添加到`Binder::bind`
- 在某些循环内使用vector.push_back时出现分段错误
- 当vector是tje全局变量时,c++中vector的内存管理
- std::vector的包装器,使数组的结构看起来像结构的数组
- 为什么(-1)%vector::size()总是返回0
- 在C++中将类(带有Vector成员)保存为二进制文件
- Why is UINT32_MAX + 1 = 0?
- C++错误:"error: int aaa::bbb is protected within this context"
- What is std::vector::_emplace_back_slow_path / std::vector::
- "error: subscripted value is not an array, pointer, or vector",我正在使用字符串
- Matlab's is empty for a std::vector ( C++)
- std::vector is索引总是更快
- Is std::vector::begin() - 1 undefined?
- 在给定的代码示例中,在 vector::p ush_back() 中"the argument is copied (or moved)"到底是什么意思?
- 向量:类模板的参数列表:"std::vector is missing"
- Vector is returned empty