【问题标题】:How to get at a C++ Container<T>'s T if no Container::value_type is provided?如果没有提供 Container::value_type,如何获得 C++ Container<T> 的 T?
【发布时间】:2021-03-08 22:52:48
【问题描述】:

容器模板包含value_type typedef 是很常见的。这使得创建其他模板化代码变得容易,最近的概念,如果只给出Container而不是Container&lt;T&gt;,就能够提取T

但是,并非所有容器(或其他模板类)都定义了这样的value_type,尤其是较旧的容器。 即使没有它,是否有可能到达包含的T

我知道有一些技巧,比如“如果它是一个迭代器,那么 .begin() 应该返回那个类型的值”,但这对我们没有帮助。编写一个概念要求,检查一个类的.begin() 是否确实遵循迭代器的要求。

【问题讨论】:

  • 我不认为这是可能的,没有一些先决条件(value_type 类型,begin() 方法,T 类型在模板参数列表的第一个位置......或其他东西否则)对于大多数但不是所有可能和可想象的容器都是如此。但是……也许我错了。
  • 如果typename std::iterator_traits&lt;std::remove_cvref_t&lt;decltype(begin(c))&gt;&gt;::value_type; 无效,则begin(c) 在技术上不是迭代器。在某些时候,您需要划清界限,您愿意在多大程度上支持类似于迭代器但不遵循现代技术要求的东西。
  • value_type 是什么 应该仔细考虑。我们可以在ClassTemplate&lt;T, ...&gt; 中得到T,从std::iterator_traits&lt;std::remove_cvref_t&lt;decltype(std::begin(cont))&gt;&gt; 中得到value_type,或者得到std::remove_cvref_t&lt;decltype(cont[0])&gt;,但实际上你想要的是哪个?如果你只是想适应旧的容器设计,我认为使用operator[]的那个更好。
  • 谢谢大家!我非常同意,只要有可能,最好改用容器类。

标签: c++ templates containers c++-concepts template-templates


【解决方案1】:

这是一个类似于 Quimby's solution 的解决方案,但使用了部分模板特化:

template<typename...>
struct inner_type_impl;

template<template<typename...> typename C, typename T, typename...Args>
struct inner_type_impl<C<T,Args...>>
{
    using type = T;
};

template<typename T>
using inner_type = typename inner_type_impl<T>::type;

这是从 Quimby 的解决方案中借用的 demo

【讨论】:

  • 很好 :) ,我懒得写其他选项。我认为这个结果也更具可读性。
  • @Quimby 是的,我发现专业化更容易阅读:) 我想这是一个品味问题。
  • 非常好!我喜欢你和@Quimby 的解决方案。我接受了这个,因为我同意它更具可读性:-)。
【解决方案2】:

可以使用类模板特化或模板参数推导来实现这一点。只要内部类型是第一个模板参数,类似以下的内容就应该起作用:

#include <type_traits>

// Consider the first template argument to be the inner type.
template<template<typename,typename...>class C,typename T,typename...Args>
auto inner_type_impl(const C<T,Args...>* v)->T*{return nullptr;};

template<typename T>
using inner_type = std::remove_pointer_t<decltype(inner_type_impl((T*)nullptr))>;


template<typename T>
struct Container;

// Will still deduce T
template<typename T,typename...Extras>
struct ContainerExtraParams;

static_assert(std::is_same_v<int,inner_type<Container<int>>>);
static_assert(std::is_same_v<int,inner_type<ContainerExtraParams<int,double,float>>>);

我也使用指针使代码在评估的上下文中有效。与涉及std::declval 的可能解决方案相反。

【讨论】:

  • 是我闲置太久还是推理一直都能做到这一点?我确信在这种情况下它无法推断出类模板。 (我必须尝试一下才能相信它!)
  • @KenWayneVanderLinde 示例中的大多数内容是 C++11 及更高版本,但模板推导本身即使在 C++98 中也有效。不确定它是否有任何变化。
猜你喜欢
  • 1970-01-01
  • 2020-11-03
  • 2018-12-04
  • 1970-01-01
  • 2020-08-15
  • 2021-04-30
  • 1970-01-01
  • 1970-01-01
  • 2014-09-06
相关资源
最近更新 更多