如何推导迭代器模板类型或其模板的嵌套类型?

时间:2012-08-15 09:48:47

标签: c++ templates c++11

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

假设我声明了以下类型

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中包含的对象?另一种选择就像普通指针一样,但我并不热衷于此。
  4. 标题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,这有点麻烦。我希望避免这种情况。看起来我错了,但是为了教育的目的,是否有可能进一步减少输入数字类型并从迭代器推导出来的需要?

1 个答案:

答案 0 :(得分:0)

侵入式解决方案是让some_type公开其类型参数,方式std::unique_ptr<T, D>通过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;

value_type中的build_instances别名将改为

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

作为最后的评论,我发现build_instance采用T参数但构造some_type<T>的实例有点奇怪。如果TT的构造实例(可能T被限制为some_type的特化)。这也可以避免您的问题。