2

我想在代码块中选择数据类型时更加迂腐,我需要在一般类型或容器类型之间进行选择。我的问题是,如果我有以下代码块,我不知道该怎么做。有人可以帮忙吗?size_type size_tcontainer::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 与 container::size_typesize_t之间container::size_type的区别。我还阅读了在编译时确定一个类型是否是 STL 容器,但这种方法对我的情况来说有点笨拙。

4

5 回答 5

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;
    // ...
}

注意:开关和糖衣层可以混合在一起,但是我想你可能会喜欢单独看到这些步骤。

于 2012-10-21T13:00:20.797 回答
4

以下是确定 a 是否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_typeor some_container::size_type,如果有的话。

于 2012-10-21T12:31:47.830 回答
2

如果它没有 asize_type那么它不是一个容器。时期。

该标准要求所有容器都应定义一个名为size_type. 来自 N3337,23.2.1 通用容器要求 [container.requirements.general]:

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

所以你的代码可以简单地看起来像:

typename some_container::size_type variable_x;
于 2012-10-21T12:15:23.050 回答
0

你可以而且你应该使用typename some_container::size_type它,即使是大多数 STL 编译器 typedef size_typesize_t但正如你所说,使用这种技术你可以支持自定义容器

于 2012-10-21T12:03:07.190 回答
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 所做的一样,在这种情况下,方法的参数必须不同,以避免歧义。

于 2014-05-29T14:11:56.773 回答