我来自Haskell,目前正在研究C++ 11,以了解它可以做什么。我的玩具之一是一个小的模板,它试图模仿Haskell map函数,即,它接受一个X值的容器,以及一个将X映射到Y的函数,并产生一个Y的值的容器。我知道我可以使用std::transform轻松地做到这一点,但这会破坏乐趣。

现在,我的模板如下所示:

template <typename T, typename U>
void myMap( const T &input,
            U &output,
            std::function<typename U::value_type (typename T::value_type)> f );

现在,我的问题是:是否可以调整签名,以便代替通过引用获取输出容器(第二个参数),而是通过返回值生成一个新容器,而编译器可以推断出返回类型?就像是
template <typename T, typename U>
U myMap( const T &input,
       std::function<typename U::value_type (typename T::value_type)> f );

不幸的是不能这样称呼
std::vector<int> x = { 1, 2, 3, 4 };
std::list<bool> y = myMap( x, []( int x ) { return x % 2 == 0; } );

...至少Clang无法在此推断出返回类型。

我的一个想法是,鉴于输入容器类型和函数类型是已知的,您可以从中构造输出类型。 IE。就像是
template <typename C, typename T, typename U>
C<U> myMap( const C<T> &input,
            std::function<U (T)> f );

...但是可惜C<U>甚至似乎都不是有效的语法。我想知道是否像this question一样需要正确的decltype仙尘。

最佳答案

您可能正在寻找这种语法

#include <algorithm>
#include <functional>
#include <type_traits>
#include <list>

template
    <
       template<typename, typename...> class Container,
       typename InType,
       typename FuncType,
       typename... Rest
    >
auto myMap (const Container<InType, Rest...>& container,
            FuncType func) ->
              Container<decltype(func(std::declval<InType>())), Rest...>
{
    Container<decltype(func(std::declval<InType>())), Rest...> result;
    std::transform(std::begin(container),
                   std::end(container),
                   std::back_inserter(result),
                   func);
    return result;
}

尽管我不建议在任何实际项目中使用这种样式的代码。

10-08 08:23
查看更多