c++ 我如何得到向量中元素的类型?

62lalag4  于 2023-03-09  发布在  其他
关注(0)|答案(5)|浏览(139)

考虑模板元编程技术

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

这是可行的,主要是因为构造函数没有标记为explicit,换句话说,我的push_back不是类型安全的。
现在,我甚至不知道容器v是如何声明的,在本例中它是int,但我需要在拥有泛型std::vector<T>时自动推导类型。
在C++11中有类似remove_all_extents的东西(有一个有用的成员type),但显然它只对旧数组有用,但这基本上是我想要实现的。
我想在push_back不是类型安全的时候触发一个错误,或者推导出类型,这样我就可以自己写一个Assert或者实现一些东西。
我真的找不到一个有效的解决方案,理论上很简单,但是一旦声明了一个向量,就没有关于元素类型的显式信息了。
我还希望避免显式的类型推断,例如从我的理想函数调用转换foo

foo( container, elements ... )

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

其中intcontainer元素的类型,在我看来,这也不安全,而且更冗长,更容易出错。
那么在C++11中如何获取容器元素的类型呢?

sxissh06

sxissh061#

你可以得到这样的类型:

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
ycggw6v2

ycggw6v22#

如果你有C++11特性,你也可以使用decltype关键字来简化对底层value_type类型成员的访问:

decltype(TheContainer)::value_type nVarOfType;

在这里,TheContainer可以是任何类型的容器。例如,map<int, string>deque<float>或任何其他STL容器-所有STL容器都有value_type类型定义。decltype键将给予给定对象的类型。

kuarbcqp

kuarbcqp3#

如果我理解正确的话,你也可以试试:

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`

虽然语法看起来很奇怪,但如果参数包Args中的所有类型都具有其复制构造函数不会抛出的属性,则上面的const表达式的计算结果为true
给定helper类模板all_of,我们现在可以只在参数包中的 all 类型等于容器的value_type时启用函数模板foo

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
}
dy2hfwbg

dy2hfwbg4#

我知道这个问题已经存在了一段时间,但为了完整起见,另一个问题

方法,它不依赖于向量是否为空

主要的想法是得到一个原始指针并衰减它的类型。显然这也适用于C风格的数组,除此之外,这几乎适用于任何数据类型。

#include <type_traits>
#include <vector>
#include <iostream>

template <class T>
using decay_all_t = 
typename std::remove_cvref<typename std::remove_pointer<T>::type>::type;

struct MyStruct {...};

int main {
    std::vector<MyStruct> j {...};

    auto *_ = j.data();
    using type = decay_all_t<decltype(_)>;

    std::cerr << typeid(type).name() << '\n';
}
fzwojiic

fzwojiic5#

您可能需要考虑使用std::ranges::range_value_t〈* 容器名称 作为直接使用容器类型 *::value_type的替代方法。

相关问题