我可以默认此Transform模板函数的返回类型吗?

时间:2015-08-06 21:20:54

标签: c++ templates

目前,要使用以下内容......

template< class ResultCollection, class Collection, typename Transformation >
ResultCollection Transform(const Collection& c, Transformation t)
{
    ResultCollection result(c.size());
    transform(c.begin(), c.end(), result.begin(), t);
    return result;
}

...您需要提供返回类型:

auto result = Transform< std::vector<int> >( someInputCollection, [] (SomeType& element) { return ElementToInt(element); });

是否可以默认模板args,以便默认情况下你会得到一个包含lambda返回的任何类型元素的向量?

我得到了这个:

template< class Collection, typename Transformation, class ResultCollection = std::vector< std::result_of_t<Transformation> > >
ResultCollection Transform(const Collection& c, Transformation t)
{
    ResultCollection result(c.size());
    transform(c.begin(), c.end(), result.begin(), t);
    return result;
}

但是这给了我这个:

C2783: 'ResultCollection Transform(const Collection &,Transformation)' : could not deduce template argument for 'ResultCollection'

而且我不确定如何解决它。

2 个答案:

答案 0 :(得分:2)

您的代码存在两个问题。第一个缺少typename s:

class ResultCollection = std::vector< typename std::iterator_traits<typename Collection::iterator>::value_type > 
                                      ^^^^^^^^                      ^^^^^^^^

但第二个是你传的错误类型!如果你的Transformation实际上并没有改变集合的值类型,那么这一切都很好,但如果这样做会怎么样?

std::vector<char> collection;
auto result = Transform(collection, [](char c) { return std::string(c, 1); });

您需要生成的vector包含Transformation提供的类型:

class ResultCollection = std::vector<
    std::result_of_t<Transformation(decltype(*std::declval<Collection>().begin()))>
>

而且,顺便说一下,如果结果类型不是默认构造的,该怎么办?你假设它在这里:

ResultCollection result(c.size());

可能想要这样做:

ResultCollection result;
result.reserve(c.size());
std::transform(c.begin(), c.end(), std::back_inserter(result), t);

或者真的:

ResultCollection result;
result.reserve(c.size());
for (const auto& elem : c) {
    result.push_back(t(elem));
}

答案 1 :(得分:1)

您可以使用kennytmthis answer提供的function_traits来获取lambda的返回类型并将其设置为默认值。使用它你会得到

template <typename T>
struct function_traits
    : public function_traits<decltype(&T::operator())>
{};
// For generic types, directly use the result of the signature of its 'operator()'

template <typename ClassType, typename ReturnType, typename... Args>
struct function_traits<ReturnType(ClassType::*)(Args...) const>
// we specialize for pointers to member function
{
    enum { arity = sizeof...(Args) };
    // arity is the number of arguments.

    typedef ReturnType result_type;

    template <size_t i>
    struct arg
    {
        typedef typename std::tuple_element<i, std::tuple<Args...>>::type type;
        // the i-th argument is equivalent to the i-th tuple element of a tuple
        // composed of those arguments.
    };
};

template< class Collection, typename Transformation, class ResultCollection = std::vector< typename function_traits<Transformation>::result_type > >
ResultCollection Transform(const Collection& c, Transformation t)
{
    ResultCollection result(c.size());
    transform(c.begin(), c.end(), result.begin(), t);
    return result;
}

你可以看到它在 Live Example

中运行