是否可以写一个类型的特点,它的值是所有常见的STL结构真(例如, vector
, set
, map
,...)?
要开始,我想写一类特质是一个真正的vector
,否则为假。 我想这一点,但它不会编译:
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
。
Answer 1:
看,用于检测STL状容器的另一基于SFINAE-溶液:
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
等),你应该这样做此 。
Answer 2:
你会说,这应该是比简单的...
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
是在其被使用的上下文非抵扣。
Answer 3:
事实上,一些试验和错误之后,我发现这是相当简单:
template<class T>
struct is_vector<std::vector<T> > {
static bool const value = true;
};
我还是想知道如何编写一个更一般的is_container
。 我必须用手工列出所有类型?
Answer 4:
而在这里,尝试猜一类是一个容器或没有其他的答案可能会为你工作,我想和命名要返回真正的类型的替代方案为您呈现。 你可以用它来构建任意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>
无论您添加到您的规则类。
Answer 5:
为什么不这样做的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等-人,只是使用偏特像我上面做了,但它仅限制于一个容器类型,而不是很多。
Answer 6:
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 { };
Answer 7:
我喜欢的东西检测是否是容器的方法是寻找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 {};
Answer 8:
快进到2018和C ++ 17,我是那么的大胆,以改善@Frank答案
// 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
。
Answer 9:
在我们的项目,我们仍然没能迁移到编译器支持C ++ 11,所以对于容器对象的type_traits我只好写了一个简单的升压风格帮手:
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 {};
Answer 10:
如果你也想使它成为常量性病工作:: 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会失败。 但是,当然这取决于你的需要。 这里的事情是,根据规格,为const和volatile的std :: is_same检查也匹配。
文章来源: How to write a type trait `is_container` or `is_vector`?