C++ 在size\u t和container::size\u类型之间选择编译时

C++ 在size\u t和container::size\u类型之间选择编译时,c++,c++11,visual-studio-2012,typetraits,size-type,C++,C++11,Visual Studio 2012,Typetraits,Size Type,我想在代码块中选择数据类型时更迂腐一些,我需要在size\u-typesize\u-t中进行选择,或者在容器类型中选择container::size\u-type。我的问题是,如果我有下面的代码块,我不知道怎么做。那里有人能帮忙吗 template<typename some_container> int func(some_container& input) { //Some code... //... decltype(input.size())

我想在代码块中选择数据类型时更迂腐一些,我需要在
size\u-type
size\u-t
中进行选择,或者在容器类型中选择
container::size\u-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...
}
模板
int func(某些容器和输入)
{
//一些代码。。。
//...
decltype(input.size())变量_x;//如果已定义,请选择此变量,
size\u t变量\u x;//否则选择此
//…更多的代码。。。
}

在这种情况下,
某些容器
可能是自定义容器,并且不提供
size()
功能。让我产生这种想法的是阅读
size\u t
container::size\u type
at之间的差异。我也读过,但这种方法对我的情况来说有点苛刻。

你可以而且应该使用
typename some\u container::size\u type
,即使大多数STL编译器都将typedef
size\u-type
作为
size\u-t
,但正如您所说,使用这种技术,您可以支持自定义容器

如果它没有
size\u-type
则它不是容器。句号

该标准要求所有容器都应定义一个名为
大小\u type
的类型。摘自N3337,23.2.1一般容器要求[容器.要求.一般]:

表达式:
X::size\u type

返回类型:无符号整数类型
断言:
size\u type
可以表示
差异类型

复杂性:编译时

因此,您的代码可以简单地如下所示:

typename some_container::size_type variable_x;

以下是确定
是否包含类型(例如
大小\类型
)的一种方法:

模板
结构具有\u大小\u类型
{
typedef字符(&yes)[2];
模板静态是测试(typename C::size_type*);
模板静态字符测试(…);
静态常量布尔值=sizeof(测试(0))==sizeof(是);
};
以下是选择两种类型的方法:

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; };
模板结构Bool;
模板
结构集{typedef size_type;};
模板
结构集{typedef typename T::size_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; };
模板
结构void{typedef void type;};
模板
结构集
{typedef 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;
}
模板
int func(某些容器和输入)
{
typedef typename Set::type type;
}

所以现在
type
要么是
size\u-type
要么是
some\u-container::size\u-type
,如果有的话。

使用
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>());
//每个大小\u类型源一个助手
模板
自动大小\类型\替换(T常量和T)->decltype(T.size());
自动大小\类型\ alt(…)->std::大小\ t;
//助手之间的切换
模板
自动大小类型切换()->decltype(大小类型切换(std::declval{}));
//和语法糖
模板
使用size_type=decltype(size_type_开关());
用法:

template <typename T>
void some_algorithm(T const& t) {
    size_type<T> const size = 0;
    // ...
}
模板
void some_算法(T const&T){
大小\类型常量大小=0;
// ...
}
注意:开关和糖衣层可以混合在一起,但是我想您可能会喜欢单独查看步骤。

使用@的答案作为起点,我使用SFINAE来确定是否存在T::size_类型,而不是检查
size()
。非常相似,只是避免了
自动

/** 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>()));
如果未定义T::size\u类型,
/**将失败。*/
模板
typename T::size\u type SizeType(常量T&&T);
/**退回到已知的大小*/
模板
标准:尺寸尺寸类型(常数t&t);
...
使用size_type=decltype(SizeType(std::declval());

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

如果
某个容器
是一个自定义容器,它可能包含也可能不包含
大小类型
@iammilind:如果自定义类型不满足容器要求,则它们不是容器。例如,它们可能无法与标准库容器适配器等一起使用。。。换句话说,根据定义,容器是一种满足容器要求的类型。@iammilind:即使是标准库中看起来像容器(基本字符串)的某些类型也不是真正的容器,因为它们不满足所有要求(交换使迭代器无效,假设为PODs)。如果提问者使用这个词“容器”是指“满足我自己定义的要求,低于标准容器要求的东西”,那么他有几个选择。最明显的是在要求中添加
size\u type
,但如果由于遗留原因无法实现,那么iammilind的SFINAE方法可以测试。这样做的风险(通常是隐式接口)是指如果
size\u type
不是类型
some\u container
的定义接口的一部分,那么谁能说这些类型的实现者不会将该名称用于不相关的东西呢?@Veksi:最可靠的方法是编写一个包装器()对于每个本身是标准容器的杂项类。或者至少实现您想要使用的容器需求子集。这样,您可以在一个位置处理每个类型的非标准性,而不是在使用它们的每个函数中。通过这种设计,如果您想编写可运行的模板包装,您可以在多种类型上,通过检测他们喜欢iammalind的答案,也可以查看
boost::ena
/** 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>()));