在编译时选择size_t和container :: size_type

时间:2012-10-21 12:00:18

标签: c++ c++11 visual-studio-2012 typetraits size-type

我想在一个代码块中选择数据类型更迂腐,我需要在 size_type size_t之间进行选择,或container::size_type对于容器类型。我的问题是,如果我有以下代码块,我不知道该怎么做。有人可以帮忙吗?

template<typename some_container>
int func(some_container& input)
{
    //Some code...
    //...
    decltype(input.size()) variable_x; //Choose this if defined,
    size_t                 variable_x; //otherwise choose this
    //... Some more code...
}

在这种情况下,some_container可能是自定义容器,但不提供size()功能。让我想到这个想法的原因是在size_t vs container::size_type阅读size_tcontainer::size_type之间的区别。我也读过Determine if a type is an STL container at compile time,但这种做法对我的情况感觉有点笨拙。

5 个答案:

答案 0 :(得分:5)

你使用decltype是正确的方法,诀窍是使用SFINAE,这可以使用模板类或函数重载轻松完成。我将展示函数方式,因为它在C ++ 11中非常简单:

// One helper per size_type source
template <typename T>
auto size_type_alt(T const& t) -> decltype(t.size());

auto size_type_alt(...) -> std::size_t;

// The switch between helpers
template <typename T>
auto size_type_switch() -> decltype(size_type_alt(std::declval<T>{}));

// And syntactic sugar
template <typename T>
using size_type = decltype(size_type_switch<T>());

用法:

template <typename T>
void some_algorithm(T const& t) {
    size_type<T> const size = 0;
    // ...
}

注意:开关和糖衣层可以混合在一起,但我想你可能会欣赏这些步骤。

答案 1 :(得分:4)

以下是确定class是否包含某种类型(例如size_type)的一种方法:

template <typename T> 
struct Has_size_type
{
  typedef char (&yes)[2];

  template <typename C> static yes test(typename C::size_type*);
  template <typename> static char test(...);

  static const bool value = sizeof(test<T>(0)) == sizeof(yes);
};

以下是两种类型之间的选择方式:

template<bool> struct Bool;
template<typename T, typename = Bool<true> >
struct Set { typedef size_type type; };
template<typename T>
struct Set<T,Bool<Has_size_type<T>::value> > { typedef typename T::size_type type; };

编辑开始:这是另一种更简单的方法:

template<typename T>
struct void_ { typedef void type; };

template<typename T, typename = void>
struct Set 
{ typedef size_type type; };

template<typename T>
struct Set<T,typename void_<typename T::size_type>::type>
{ typedef typename T::size_type type; };

修改结束

最后,使用如下:

template<typename some_container>
int func(some_container& input)
{
  typedef typename Set<some_container>::type type;
}

所以现在typesize_typesome_container::size_type,如果有的话。{/ p>

答案 2 :(得分:2)

如果它没有size_type,则它不是容器。周期。

标准要求所有容器都应定义名为size_type的类型。从N3337,23.2.1一般容器要求[container.requirements.general]:

  

表达式: X::size_type
  返回类型:无符号整数类型
  断言: size_type可以表示任何非负值   difference_type
  复杂性:编译时间

因此,您的代码可以简单地看作:

typename some_container::size_type variable_x;

答案 3 :(得分:0)

您可以并且应该使用typename some_container::size_type,即使大多数STL编译器也将size_type命名为size_t,但正如您所说,使用此技术可以支持自定义容器

答案 4 :(得分:0)

使用@ Matthieu M.的答案作为起点,我使用SFINAE来确定是否存在T :: size_type,而不是检查size()。非常相似,只是避免使用auto

/** Fails if T::size_type isn't defined. */ 
template <class T>
typename T::size_type SizeType(const T &&t);

/** Fallback to a known size. */
template <class T>
std::size_t SizeType(const T &t);

...

using size_type = decltype(SizeType<T>(std::declval<T>()));

与Matthieu一样,在这种情况下,方法的参数必须不同,以避免歧义。