C++ 函数模板作为参数

C++ 函数模板作为参数,c++,templates,c++11,function-pointers,C++,Templates,C++11,Function Pointers,我一直在尝试用C++11实现Python中的函数。它似乎适用于任何类型的可调用对象,但如果我希望它适用于函数模板,则必须指定模板类型参数。例如: #include <iostream> #include <list> template<typename T> T abs(T x) { return x < 0 ? -x : x; } int main() { std::list<int> li = { -1, -2, -3

我一直在尝试用C++11实现Python中的函数。它似乎适用于任何类型的可调用对象,但如果我希望它适用于函数模板,则必须指定模板类型参数。例如:

#include <iostream>
#include <list>

template<typename T>
T abs(T x)
{
    return x < 0 ? -x : x;
}

int main()
{
    std::list<int> li = { -1, -2, -3, -4, -5 };
    for (auto i: map(&abs<int>, li))
    {
        std::cout << i << std::endl;
    }
}
我的
map
函数写为:

template<typename Callable, typename Container>
auto map(const Callable& function, Container&& iter)
    -> MapObject<Callable, Container>
{
    return { function, std::forward<Container>(iter) };
}
模板
自动映射(常量可调用函数、容器和iter)
->MapObject
{
返回{function,std::forward(iter)};
}

其中
MapObject
是实现的一部分,在这里不是真正的问题。如何更改其定义,以便从
容器
对象推断出
可调用
对象的模板类型?例如,
map
如何知道在给定
list
时,我们必须对给定的
abs
使用
abs

它不会推断它,因为您从未指定Callable是一个模板。您将Callable设置为模板参数,它应该为您推断其类型

template<template <typename T> typename Callable, typename Container>
auto map(const Callable<T>& function, Container&& iter)
    -> MapObject<Callable<T>, Container>
{
    return { function, std::forward<Container>(iter) };
}
模板
自动映射(常量可调用函数、容器和iter)
->MapObject
{
返回{function,std::forward(iter)};
}
但是,您可能会被咬,因为您无法获取仍要实例化的模板的地址。不知道你为什么需要…的地址

它工作正常,但我希望它能够从函数的第二个参数推断int参数,因此能够编写:

for (auto i: map(&abs, li))
{
    std::cout << i << std::endl;
}

我在Python中有轻微作弊,它将创建一个不同的容器,但C++中的代码>转换< /COD>在迭代器级别工作,不知道容器,但同样可以得到同样的效果:

std::vector<int> v{1,2,3};
std::vector<int> result;
// optionally: result.reserve(v.size());
std::transform(v.begin(),v.end(),
               std::back_inserter(result),
               [](int x) { return 2*x; });
这比您尝试执行的操作更不通用,因为它只接受函数指针和具体类型(这甚至比
std::transform
更不通用),并且它的工作原理就像编译器看到
abs
(没有
&
)时,它会将其解析为模板,从而解析为一组专门化。然后,它将使用预期的类型选择一个专门化并传入。在这种情况下,编译器将隐式地为您执行
&abs

另一个更通用的替代方法不是使用函数,而是使用函子。记住这一点,您可以将abs定义为:

struct abs {
   template <typename T>
   T operator()(T t) { ...}
};
其中,额外的一组括号用于创建类型为
abs
的对象并将其传入

总的来说,我会尽量避免这种情况。这是一个有趣的事情,你可能会得到一个很好的解决方案,但这将是困难的,需要相当多的C++专业知识。因为该语言不支持它,所以您必须设计在该语言中工作的东西,并且需要在不同的特性或语法上进行折衷。了解选择本身是一个困难的问题,更难理解妥协,更难找到好的解决方案。好的解决方案可能会比等价的惯用C++代码差。

如果你用C++编程,程序C++。试图通过C++编译器对Python进行编码可能会给你带来C++的痛苦和Python的性能。

你可以使用<代码> t=容器::ValueEyType < /Cord>并添加一个专门化的代码> T(t)< /C>……@ KerrekSB,我想保持当前与C数组的兼容性。因为
std::abs
甚至不是可调用的,所以它只是一个模板。你可以做一些有线的事情,比如
map(li)
,但我不认为这会更好。
std::abs
是一个模板吗?在a
C
标题中定义?嗯<代码>std::transform(li.begin(),li.end(),std::ostream_迭代器(std::cout,“\n”),[](int x){return abs(x);})如果我记得清楚的话,我们不能在真实代码中使用
t
参数。+1我不知道传递模板名称并让编译器推断专门化是可能的。@DyP:这只是我这边不精确的措辞:)你真的在传递一个函数,编译器只是在为你挑选一个。虽然大多数人没有意识到这一点,但这是经常做的:
std::cout很棒的答案,我真的很喜欢它!我学到了一些我以前不知道的东西。谢谢!你真的只是传递一个函数吗?我的意思是,您正在传递模板的名称,因此编译器可能必须在使用它之前实例化它;也就是说,它不仅仅是一组固定函数的过载解决方案。“我建议你学习语言中的习语”——我认为,试图用C++来实现功能性的IDE是一个很好的目标,因为C++当然可以以功能性的方式使用——只是支持还不太充分(我希望能弥补)。此外,Range还将带来更多的功能性风格(就像Boost.Range已经做到的那样)。
std::vector<int> v{1,2,3};
std::vector<int> result;
// optionally: result.reserve(v.size());
std::transform(v.begin(),v.end(),
               std::back_inserter(result),
               [](int x) { return 2*x; });
template <typename Container>
auto map(Container && c, 
         typename Container::value_type (*f)(typename Container::value_type))
     -> MapObject<Callable<T>,Container>;
template <typename T>
T abs(T value);

int main() {
   std::vector<int> v{1,2,3,4};
   map(v,abs);
}
struct abs {
   template <typename T>
   T operator()(T t) { ...}
};
for (auto& element : map(container,abs()))