让我们说您有一个模板函数,该函数需要一个“集合”,并且可能需要一个“转换” lambda:
template<typename Collection, typename Transform>
void DoIt(const Collection &c, Transform transform)
{
for(auto &item: c)
{
std::cout << transform(item);
}
}
但是我想要一个默认的lambda转换,该转换只是返回对其参数的引用。这样,如果Collection :: value_type支持<<到流中,则只需调用
DoIt(collection);
但如果没有,您可以致电:
DoIt(collection, [](const collection::value_type &item) { item.ToString();});
答案 0 :(得分:4)
最简单的答案可能是重载该函数,然后调用另一个:
template<typename Collection, typename Transform>
void DoIt(const Collection &c, Transform transform)
{
for(auto &item: c)
{
std::cout << transform(item);
}
}
template<typename Collection>
void DoIt(const Collection &c)
{
DoIt(c, [](auto &item) -> decltype(item) { return item; });
}
或者如果由于某种原因确实只需要一个模板,则需要一个类似函数的类,该类仅通过其参数传递。
namespace std_compat {
struct identity
{
template<typename T>
constexpr T&& operator()(T&& obj) const noexcept
{ return std::forward<T>(obj); }
using is_transparent = void;
};
}
template<typename Collection, typename Transform = std_compat::identity>
void DoIt(const Collection &c, Transform transform = {})
{
for(auto &item: c)
{
std::cout << transform(item);
}
}
这也允许用户执行类似DoIt<decltype(c), std::negate<>>(c);
的操作。这似乎并不特别好或坏。
注意std::identity
随C ++ 20一起提供。
答案 1 :(得分:2)
// Function object that returns a reference to x
struct SelfReference
{
template<class T>
auto operator()(T& x) const -> T&
{
return x;
}
};
// default template argument selects SelfReference
// also note default argument
template<typename Collection, typename Transform = SelfReference>
void DoIt(const Collection &c, Transform transform = Transform())
{
for(auto &item: c)
{
std::cout << transform(item);
}
}