我想在一个代码块中选择数据类型更迂腐,我需要在 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_t
和container::size_type
之间的区别。我也读过Determine if a type is an STL container at compile time,但这种做法对我的情况感觉有点笨拙。
答案 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;
}
所以现在type
是size_type
或some_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一样,在这种情况下,方法的参数必须不同,以避免歧义。