Xan*_*lip 18 c++ templates stl template-meta-programming
我想编写一个模板来确定类型是否是编译时的stl容器.
我有以下一点代码:
struct is_cont{};
struct not_cont{};
template <typename T>
struct is_cont { typedef not_cont result_t; };
Run Code Online (Sandbox Code Playgroud)
但我不确定如何创建必要的专业化std::vector<T,Alloc>, deque<T,Alloc>, set<T,Alloc,Comp>等...
Naw*_*waz 23
注意:以下代码取自@Kerrek SB编写的一个名为pretty-print的优秀实用程序(stackoverflow上的一个主题).
免责声明:我不知道是否允许在未经原作者许可的情况下复制并粘贴此代码.@Kerrek,如果您有任何问题,请告诉我.:-)
您可以使用此类模板:
template<typename T>
struct is_container : std::integral_constant<bool, has_const_iterator<T>::value && has_begin_end<T>::beg_value && has_begin_end<T>::end_value>
{ };
Run Code Online (Sandbox Code Playgroud)
用法:
std::cout << is_container<std::vector<int>>::value << std::endl; //true
std::cout << is_container<std::list<int>>::value << std::endl; //true
std::cout << is_container<std::map<int>>::value << std::endl; //true
std::cout << is_container<std::set<int>>::value << std::endl; //true
std::cout << is_container<int>::value << std::endl; //false
Run Code Online (Sandbox Code Playgroud)
请注意,is_container需要遵循帮助程序类模板:
template<typename T>
struct has_const_iterator
{
private:
typedef char yes;
typedef struct { char array[2]; } no;
template<typename C> static yes test(typename C::const_iterator*);
template<typename C> static no test(...);
public:
static const bool value = sizeof(test<T>(0)) == sizeof(yes);
typedef T type;
};
template <typename T>
struct has_begin_end
{
template<typename C> static char (&f(typename std::enable_if<
std::is_same<decltype(static_cast<typename C::const_iterator (C::*)() const>(&C::begin)),
typename C::const_iterator(C::*)() const>::value, void>::type*))[1];
template<typename C> static char (&f(...))[2];
template<typename C> static char (&g(typename std::enable_if<
std::is_same<decltype(static_cast<typename C::const_iterator (C::*)() const>(&C::end)),
typename C::const_iterator(C::*)() const>::value, void>::type*))[1];
template<typename C> static char (&g(...))[2];
static bool const beg_value = sizeof(f<T>(0)) == 1;
static bool const end_value = sizeof(g<T>(0)) == 1;
};
Run Code Online (Sandbox Code Playgroud)
Vau*_*ato 16
首先,定义主模板,在默认情况下,该模板的成员为false:
template <typename T>
struct is_cont {
static const bool value = false;
};
Run Code Online (Sandbox Code Playgroud)
然后,您将为容器类型定义部分特化,其值为true:
template <typename T,typename Alloc>
struct is_cont<std::vector<T,Alloc> > {
static const bool value = true;
};
Run Code Online (Sandbox Code Playgroud)
然后对于要检查的类型X,请使用它
if (is_cont<X>::value) { ... }
Run Code Online (Sandbox Code Playgroud)
Tre*_*key 12
许多已提出的解决方案对于检测STL容器而言都很冗长.
他们专注于所有容器所具有的特性,而不是明确说明容器是什么.
如果您想创建自己的容器并使用真实类型进行评估,我建议使用其他解决方案.如果您只想验证合法的STL容器,而不是类似STL的容器,请考虑使用以下实现,因为它提供了精确的STL容器检测:
#include <deque>
#include <forward_list>
#include <list>
#include <map>
#include <queue>
#include <set>
#include <stack>
#include <string>
#include <tuple>
#include <type_traits>
#include <unordered_map>
#include <unordered_set>
#include <utility>
#include <vector>
#include <type_traits>
//specialize a type for all of the STL containers.
namespace is_stl_container_impl{
template <typename T> struct is_stl_container:std::false_type{};
template <typename T, std::size_t N> struct is_stl_container<std::array <T,N>> :std::true_type{};
template <typename... Args> struct is_stl_container<std::vector <Args...>>:std::true_type{};
template <typename... Args> struct is_stl_container<std::deque <Args...>>:std::true_type{};
template <typename... Args> struct is_stl_container<std::list <Args...>>:std::true_type{};
template <typename... Args> struct is_stl_container<std::forward_list <Args...>>:std::true_type{};
template <typename... Args> struct is_stl_container<std::set <Args...>>:std::true_type{};
template <typename... Args> struct is_stl_container<std::multiset <Args...>>:std::true_type{};
template <typename... Args> struct is_stl_container<std::map <Args...>>:std::true_type{};
template <typename... Args> struct is_stl_container<std::multimap <Args...>>:std::true_type{};
template <typename... Args> struct is_stl_container<std::unordered_set <Args...>>:std::true_type{};
template <typename... Args> struct is_stl_container<std::unordered_multiset<Args...>>:std::true_type{};
template <typename... Args> struct is_stl_container<std::unordered_map <Args...>>:std::true_type{};
template <typename... Args> struct is_stl_container<std::unordered_multimap<Args...>>:std::true_type{};
template <typename... Args> struct is_stl_container<std::stack <Args...>>:std::true_type{};
template <typename... Args> struct is_stl_container<std::queue <Args...>>:std::true_type{};
template <typename... Args> struct is_stl_container<std::priority_queue <Args...>>:std::true_type{};
}
//type trait to utilize the implementation type traits as well as decay the type
template <typename T> struct is_stl_container {
static constexpr bool const value = is_stl_container_impl::is_stl_container<std::decay_t<T>>::value;
};
Run Code Online (Sandbox Code Playgroud)
注意使用std::decay以避免基于类型限定符的不正确类型推导.此外,我们已经利用了继承std::true_type并std::false_type避免::type自己指定类型.C++ 11可变参数模板用于推导构造容器所需的n量模板类型参数.
正如您所期望的那样使用该实现:
std::cout << std::boolalpha;
std::cout << is_stl_container<std::vector<int>>::value << '\n';
std::cout << is_stl_container<std::vector<int>const&>::value << '\n';
std::cout << is_stl_container<int>::value << '\n';
Run Code Online (Sandbox Code Playgroud)
打印:
true
true
false
Run Code Online (Sandbox Code Playgroud)
Mik*_*han 10
建议对has-an-stl-container-like-interface的通用编译时测试
是一个合适的解决方案,这个接口定义了一个类似stl的容器 T
:
T::iterator T::begin();
T::iterator T::end();
T::const_iterator T::begin() const;
T::const_iterator T::end() const;
*T::iterator is T::value_type &
*T::const_iterator is T::value_type const &
Run Code Online (Sandbox Code Playgroud)
size()可以以明显的方式添加附加要求,例如方法,或者以明显类似的方式在编译时探测其他规范类型接口.
#ifndef IS_STL_CONTAINER_LIKE_H
#define IS_STL_CONTAINER_LIKE_H
#include <type_traits>
template<typename T>
struct is_stl_container_like
{
typedef typename std::remove_const<T>::type test_type;
template<typename A>
static constexpr bool test(
A * pt,
A const * cpt = nullptr,
decltype(pt->begin()) * = nullptr,
decltype(pt->end()) * = nullptr,
decltype(cpt->begin()) * = nullptr,
decltype(cpt->end()) * = nullptr,
typename A::iterator * pi = nullptr,
typename A::const_iterator * pci = nullptr,
typename A::value_type * pv = nullptr) {
typedef typename A::iterator iterator;
typedef typename A::const_iterator const_iterator;
typedef typename A::value_type value_type;
return std::is_same<decltype(pt->begin()),iterator>::value &&
std::is_same<decltype(pt->end()),iterator>::value &&
std::is_same<decltype(cpt->begin()),const_iterator>::value &&
std::is_same<decltype(cpt->end()),const_iterator>::value &&
std::is_same<decltype(**pi),value_type &>::value &&
std::is_same<decltype(**pci),value_type const &>::value;
}
template<typename A>
static constexpr bool test(...) {
return false;
}
static const bool value = test<test_type>(nullptr);
};
#endif
Run Code Online (Sandbox Code Playgroud)
这是一个测试程序,使用GCC 4.7.2,clang 3.2,Intel C++ 13.1.1构建:
#include "is_stl_container_like.h"
// Testing ...
#include <iostream>
#include <vector>
#include <array>
#include <functional>
using namespace std;
template<class C>
struct polymorphic : private C
{
typedef typename C::value_type value_type;
typedef typename C::iterator iterator;
typedef typename C::const_iterator const_iterator;
virtual ~polymorphic(){}
virtual const_iterator begin() const {
return C::begin();
}
virtual iterator begin() {
return C::begin();
}
virtual const_iterator end() const {
return C::end();
}
virtual iterator end() {
return C::end();
}
};
template<class C>
struct reject : private C
{
typedef typename C::value_type value_type;
typedef typename C::iterator iterator;
typedef typename C::const_iterator const_iterator;
const_iterator begin() {
return C::begin();
}
iterator begin() const {
return C::begin();
}
const_iterator end() {
return C::end();
}
iterator end() const {
return C::end();
}
};
int main()
{
cout << is_stl_container_like<vector<int> const >::value << endl; // Yes
cout << is_stl_container_like<array<int,42>>::value << endl; // Yes
cout << is_stl_container_like<polymorphic<vector<int>>>::value << endl; // Yes
cout << is_stl_container_like<function<int(int)>>::value << endl; // No
cout << is_stl_container_like<int>::value << endl; // No
cout << is_stl_container_like<reject<vector<int>>>::value << endl; //No
}
Run Code Online (Sandbox Code Playgroud)
在 C++20 中,您可以使用concept,
您可以从您认为的容器中添加更多检查,但它可能看起来像:
template <typename T>
concept Container = requires(T t)
{
std::begin(t);
std::end(t);
};
Run Code Online (Sandbox Code Playgroud)
用法示例。
标准中已经存在一些您可能感兴趣的概念:
| 归档时间: |
|
| 查看次数: |
13513 次 |
| 最近记录: |