【问题标题】:How to deduce iterator template type, or its template's nested type?如何推断迭代器模板类型,或其模板的嵌套类型?
【发布时间】:2012-08-15 09:48:46
【问题描述】:

这个问题需要更多的准备,所以我先提供一些代码,然后是确切的问题

假设我声明了以下类型

template<typename T>
struct some_type
{
    T t_;
};

将使用这样的工厂函数构造

typedef float numeric_type;
std::vector<std::string> construction_material;
//Push_back of strings in certain form...
std::vector<std::unique_ptr<some_type<numeric_type>> instances;
build_instances(construction_material.begin(), construction_material.end(), back_inserter(instances));

并且构造函数将是 跟在

之后
template<typename input_iterator, typename output_iterator>
output_iterator build_instances(input_iterator begin, input_iterator end, output_iterator out)
{
    for(input_iterator iter = begin; iter != end; ++iter)
    {
        //This won't work, but to illustrate some ideas...
        //build_instance<std::iterator_traits<output_iterator>::value_type>(*iter)
    }

    //[...]

    return *out;
}

template<typename T>
std::unique_ptr<some_type<T>> build_instance(std::string const& material)
{
    static_assert(std::is_floating_point<T>::value == true, "The template type needs to be a floating point type.");

    std::unique_ptr<some_instance<T>> instance(new some_instance<T>());
    //Some processing...

    return instance;
}

我知道我可以更改函数以返回一些容器(或者甚至模板化容器类型),例如

template<typename input_iterator, typename T>
std::vector<std::unique_type<T>> build_instances(input_iterator begin, input_iterator end,       
output_iterator out)
{
    //Likewise code to the previous snippets...
    return ...
}

我没能解决的问题是:

  1. 是否有可能 - 或不可能 - 使用类似 back_inserter 的方法?看起来对调用者来说是最灵活的?
  2. 如何在 build_instances 主体中获得 numeric_type 的保留(如通过 output_iterator 获得),以便它可以用于逐个构建实例一个?
  3. 如何确保调用者知道等待包装在 std::unique_ptrs 中的对象?另一种选择就是简单的指针,但我对此并不热衷。

有一个标题为How can I make this template method more elegant? (or: less explicit template parameters required) 的类似问题,它接受一个容器并将其转换为不同类型的容器。

编辑 正如对 Jogojapan 的评论所评论的那样,目前我像这样转换输入

std::transform(construction_material.begin(), construction_material.end(), std::inserter(instances, instances.begin()), build_instance<numeric_type>);

但随后的函数调用也需要提供numeric_type typedef,这有点麻烦。我希望避免这种情况。看起来我错了,但出于教育和所有目的,是否有可能进一步减少 typedef 数字类型并从迭代器中推断出来的需要?

【问题讨论】:

  • 对于问题 2.,也许像 decltype(*((*it).front().get())) 这样的东西会起作用?
  • some_type&lt;T&gt; 的作用/意义是什么?在您的示例中,调用者准备了vector&lt;unique_ptr&lt;float&gt;&gt;,但build_instances() 似乎填写了vector&lt;unique_ptr&lt;some_type&lt;float&gt;&gt;&gt;,或者我误解了什么。此外,在build_instance() 中,您似乎将类型名称从some_type&lt;T&gt; 切换为some_instance&lt;T&gt;
  • @Moritz,我过会儿再说。
  • Jogojapan,好收获!我会编辑文字! some_type 的作用是成为一堆不同种类的token,其中type参数很重要。目前的构造类似于“std::transform(construction_material.begin(), construction_material.end(), std::inserter(instances, instances.begin()), build_instance);”我看到的问题是模板类型需要在后续函数调用中重复,因为它也是需要的。
  • 据我所知,您对 (2) 的解决方案有效 - 使用 GCC 4.6 和 -std=c++0x 为我编译的代码非常相似。为什么你认为它不起作用?

标签: c++ templates c++11


【解决方案1】:

一个侵入性的解决方案是让some_type 暴露它的类型参数,就像std::unique_ptr&lt;T, D&gt; 通过element_type 暴露它的第一个参数一样(我们稍后会用到):

template<typename T>
struct some_type
{
    // give it an appropriate meaningful name
    using value_type = T;
    value_type t_;
};

template<typename input_iterator, typename output_iterator>
output_iterator build_instances(input_iterator begin, input_iterator end, output_iterator out)
{
    using pointer_type = typename std::iterator_traits<output_iterator>::value_type;
    using value_type = typename pointer_type::element_type::value_type;
    return std::transform(begin, end, out, build_instance<value_type>);
}

您也可以非侵入式地提取模板特化的第一个模板参数:

template<typename T>
struct first;

template<template<typename...> class Template, typename First, typename... Pack>
struct first<Template<First, Pack...>>> {
    using type = First;
};

template<typename T>
using First = typename first<T>::type;

build_instances 中的 value_type 别名将改为

using value_type = First<typename pointer_type::element_type>;

最后,我觉得 build_instance 采用 T 参数但构造 some_type&lt;T&gt; 的实例有点奇怪。如果它使用T 并构造了T 的实例(其中T 可能被限制为some_type 的特化。)这也可以避免你的问题。

【讨论】:

  • 我刚醒来,我必须让它沉入我心中片刻。 :-) 我对模板有些陌生,因此这也是我使用 T 参数的原因。尽管我没有立即看到将参数从普通 T 更改为 some_type 会如何使问题消失。我想我想要做的是用户插入器用构造的实例填充一些任意容器,作为参数,而不是返回“预选容器”,比如 std::vector> .这有点失控,但话说回来,学习很好!
  • @Veksi 我刚刚意识到我的答案不完整。
  • 我需要在 g++ 上进行测试,但它看起来似乎是合理的。 VC 2012 RC 不支持可变参数模板...
  • @Veksi 您可以对first(和First)进行特殊处理,以提取一个参数模板专业化的一个参数,以满足您的需求。我展示的版本是通用的,只是为了它。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2018-06-11
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2023-03-31
相关资源
最近更新 更多