This questions begs a more preparation, so I provide some bits of code first and then the exact question
Assuming I have the following type declared
template<typename T>
struct some_type
{
T t_;
};
which would be constructed with a factory function like so
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));
and the construction function would be something like following
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;
}
I know I could change the function to return some container (or perhaps even templatize the container type), like
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 ...
}
The problems I haven't been able to solve are:
There's a similar kind of question with a heading How can I make this template method more elegant? (or: less explicit template parameters required) , which takes a container and transforms it to a different type of a container.
Edit As commented to Jogojapan's comment that currently I transform the input like so
std::transform(construction_material.begin(), construction_material.end(), std::inserter(instances, instances.begin()), build_instance<numeric_type>);
but the subsequent function calls need to be supplied the
numeric_type
typedef too, which is somewhat cumbersome.
I hope to avoid that.
It looks I was mistaken, but for the purpose of education and all, would it be possible to further reduce the need to typedef the numeric type and deduce it from the iterator?
An intrusive solution is to let some_type
exposes its type parameter, the same way std::unique_ptr<T, D>
exposes its first parameter via element_type
(which we will need later):
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>);
}
You can also non-intrusively extract the first template parameter of a template specialization:
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;
The value_type
alias in build_instances
would instead become
using value_type = First<typename pointer_type::element_type>;
As a final remark I find it a bit odd that build_instance
take a T
parameter but constructs instances of some_type<T>
. If it took T
and constructed instances of T
(where perhaps T
is restricted to be a specialization of some_type
.) This would have spared your problem, too.
The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.