如何获取向量中元素的类型?

问题描述 投票:5回答:3

考虑模板元编程技术,如果我有

std::vector<int> v;
v.push_back(42.42f);

这工作,主要是因为使用它的构造函数没有标记explicit,换句话说我的push_back它不是类型安全的。

现在我处在一种我甚至不知道如何声明容器v的情况,在这种情况下它是int,但我需要在拥有通用std::vector<T>时自动推断出类型。我想要一个解决方案来获得T

在C ++ 11中有类似remove_all_extents(有一个有用的成员type),但显然它只对旧数组有用,但它基本上是我想要实现的。

我想在push_back它不是类型安全或推断类型时触发错误,所以我可以写一个断言或自己实现一些东西。

我真的找不到一个有效的解决方案,它在理论上如此简单,但是一旦声明了一个向量,就没有关于用于元素的类型的明确信息。

我也想避免明确的类型推断,比如从我理想的函数调用中翻译foo

foo( container, elements ... )

foo<int>(container, elements ...)

其中intcontainer元素的类型,在我看来这也不安全,它也更冗长,更容易出错。

那么如何在C ++ 11中检索容器元素的类型呢?

c++ c++11 vector stl
3个回答
9
投票

你可以得到这样的类型:

typename std::vector<T>::value_type;

然后使用static_assertstd::is_same

template <typename T1, typename T2>
void special_push_back(std::vector<T1>& v, T2 elem)
{
  // check that T1 and T2 are the same before pushing elem into v
}

然后

std::vector<int> v;
special_push_back(v, 3.14); // Compile time error: double is not int

4
投票

如果您有C ++ 11功能,还可以使用decltype关键字来轻松访问value_type

decltype(TheContainer)::value_type nVarOfType;

其中TheContainer可能是任何类型的容器。例如map<int, string>deque<float>或任何其他STL容器,因为所有STL容器都具有value_type类型定义。 decltype将返回给定对象的类型。


2
投票

如果我理解正确的评论,您也可以尝试:

template <class Container, class... Args>
void foo(Container&& c, Args&&... args) {
    typedef typename Container::value_type value_type;

    // use type_traits to check value_type
    ...
}

一个改进是检查Container是否有嵌入式value_type

template <class T>
struct has_value_type
{
private:
    template <class U> static std::false_type test(...);
    template <class U> static std::true_type test(typename U::value_type*);
public:
    enum { value = decltype(test<T>(0))::value };
};

然后使用std::enable_if

template <class Container, class... Args>
typename std::enable_if<has_value_type<Container>::value, return_type>::type 
foo(Container&& c, Args&&... args) {
    typedef typename Container::value_type value_type;
    ...
}

同样,您只能“启用”满足您对值类型要求的模板:

template <class Container, class... Args>
typename std::enable_if<
    has_value_type<Container>::value
    and std::is_same<int, typename Container::value_type>::value
>::type
foo2(Container&& c, Args&&... args) {
    typedef typename Container::value_type value_type;

    // here value_type equals int
}

编辑:

通过更多“模板技巧”,您可以确保所有类型的可变参数模板包都相等,并且等于容器的value_type:

首先,帮助模板:

template <typename...>
struct all_of;

template <typename T>
struct all_of<T> : std::conditional<T::value == true,
    std::true_type, std::false_type>::type
{};

template <typename Head, typename... Tail>
struct all_of<Head, Tail...> : std::conditional<
    Head::value == true and all_of<Tail...>::value,
    std::true_type,
    std::false_type>::type
{};

没有任何进一步的代码,您可以使用它,例如,如下所示:

`all_of<std::is_nothrow_copy_constructible<Args>...>::value`

虽然语法可能看起来很奇怪,但如果参数包true中的所有类型都具有其拷贝构造函数不会抛出的属性,则上面的const表达式将计算为Args

给定辅助类模板all_of,只有当参数包中的所有类型都等于容器的foo时,我们才能启用函数模板value_type

template <class Container, class... Args>
typename std::enable_if<
    has_value_type<Container>::value
    and all_of<std::is_same<typename Container::value_type, Args>...>::value
>::type
foo2(Container&& c, Args&&... args) {
    typedef typename Container::value_type value_type;

    // here *all* types in Args are equal value_type
}
© www.soinside.com 2019 - 2024. All rights reserved.