如何写一个类型特征`is_container`或`is_vector`?

Fra*_*ank 23 c++ templates sfinae enable-if

是否可以写一个类型的特点,它的值是所有常见的STL结构真(例如vector,set,map,...)?

首先,我想编写一个类型特征,对于a vector和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;
};
Run Code Online (Sandbox Code Playgroud)

错误消息是template parameters not used in partial specialization: U.

Nev*_*ore 30

看,另一个基于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 {};
Run Code Online (Sandbox Code Playgroud)

当然,您可以更改要检查的方法和类型.

如果你想只检测STL容器(它的意思std::vector,std::list等),你应该这样做.

  • is_cointainer_helper现在可以被std :: void_t取代 (7认同)
  • 使用 `std::void_t` [你可以垃圾](https://wandbox.org/permlink/EkXKcba58vfzjeF4) `std::conditional_t`? (2认同)

Dav*_*eas 16

你会说它应该比那简单......

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;
};
Run Code Online (Sandbox Code Playgroud)

......但我不确定这是否更简单.

在C++ 11中,您可以使用类型别名(我认为,未经测试):

template <typename T>
using is_vector = is_same<T, std::vector< typename T::value_type,
                                          typename T::allocator_type > >;
Run Code Online (Sandbox Code Playgroud)

您的方法的问题是该类型U在使用它的上下文中是不可推导的.

  • @rhalbersma:问题是你对`is_container`的定义是什么......我的手把`single_list`卷成了一个容器?是`std :: string`一个容器?它有分配器的事实是否使对象成为容器? (3认同)
  • 对于`is_container`?只是测试它是否有`allocator_type`? (2认同)

Fra*_*ank 14

实际上,经过一些反复试验,我发现它非常简单:

template<class T>
struct is_vector<std::vector<T> > {
  static bool const value = true;
};
Run Code Online (Sandbox Code Playgroud)

我还是想知道如何写一个更通用的is_container.我必须手动列出所有类型吗?

  • +1 ......呃!(也许你想在那里添加`allocator_type`,因为它实际上就是`is_vector_with_default_allocator` (3认同)
  • @NoSenseEtAl 这是错误的代码。自动 isv = is_vector&lt;int&gt;::value ;是非模板结构“is_vector”的显式专业化...检查 (2认同)
  • 您首先需要错误的通用模板 https://wandbox.org/permlink/76dOGKSuvEiBdAdw (2认同)

Foz*_*ozi 7

虽然这里的其他答案试图猜测一个类是否是一个容器可能对你有用,但我想向你介绍一个命名你想要返回的类型的替代方法.您可以使用它来构建任意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 {};
Run Code Online (Sandbox Code Playgroud)

等等.

您需要包含<type_traits>您添加到规则中的任何类.


bst*_*our 7

为什么不为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 { };
// ...
Run Code Online (Sandbox Code Playgroud)

这样,用户可以通过部分专业化添加自己的容器.至于is_vector等,只是像我上面那样使用部分特化,但是只将它限制为一个容器类型,而不是很多.