【问题标题】:map C++ overloaded function over heterogenous tuple?在异构元组上映射 C++ 重载函数?
【发布时间】:2014-05-01 18:55:54
【问题描述】:

在 C++ 中,是否可以将重载函数映射到异构元组上?例如:

double f(dobule);
size_t f(std::string);

auto t = std::make_tuple(3.14, "a string");
// should be the same as std::make_tuple(f(std::get<0>(t)), f(std::get<1>(t)));
map(f, make_tuple(3.14, "a string")); // type std::tuple<double, size_t>

我可以编写一个映射函数,将f 的相同重载实例映射到每个元组元素(下面的代码),但我不知道如何将f 的重载分辨率从对@987654325 的调用中延迟@ 对f 内部map 的调用。有没有人知道如何做到这一点?

这是我将重载函数的单个实例映射到元组上的代码(其中 seq 和 gens 取自此答案 https://stackoverflow.com/a/7858971/431282):

// basically C++14's integer sequence
template<int ...>
struct seq { };

template<int N, int ...S>
struct gens : gens<N-1, N-1, S...> { };

template<int ...S>
struct gens<0, S...> {
  typedef seq<S...> type;
};

template<typename R, typename A, typename ...B, int ...S> auto
map_1(R (*f)(A), std::tuple<B...> &&t, seq<S...>)
  -> decltype(std::make_tuple(f(std::get<S>(t))...))
{
  return std::make_tuple(f(std::get<S>(t))...);
}

template<typename R, typename A, typename ...B> auto
map(R (*f)(A), std::tuple<B...> &&t)
  -> decltype(map_1(f, std::forward<std::tuple<B...>>(t), typename gens<sizeof...(B)>::type()))
{
  return map_1(f, std::forward<std::tuple<B...>>(t), typename gens<sizeof...(B)>::type());
}

【问题讨论】:

  • 我想出了一个部分解决方案:使用带有重载operator() 的可调用对象并将map 签名更改为template&lt;typename F, ...&gt; ... map(F f, ...)。不过,将作用域中的重载函数捕获为可调用对象会很好!
  • boost 已经有了这个,不是 stdlib 吗?

标签: c++ tuples overloading stdtuple


【解决方案1】:

问题在于它不能单独使用函数指针来完成,因为您希望在绑定到参数时解决函数重载。如果不执行重载解析,您将无法获得指向函数的函数指针。关键是提供一个在调用时执行重载的函数对象,而不是在开始时尝试获取函数指针。

为此,我将主要功能声明为

template<typename Func, typename ...B> auto
map(Func&& f, std::tuple<B...> &&t)
  -> decltype(map_1(std::forward<Func>(f), std::forward<std::tuple<B...>>(t), typename gens<sizeof...(B)>::type()))
{
  return map_1(std::forward<Func>(f), std::forward<std::tuple<B...>>(t), typename gens<sizeof...(B)>::type());
}

然后以类似的方式定义map_1

然后你可以做一个函数对象包装器

struct Wrapper
{
   template<typename T>
   auto operator()(T&& t) const -> decltype( f(std::forward<T>(t)) )
   {
       return f(std::forward<T>(t));
   }
};

并使用map(Wrapper(), make_tuple(3.14, "a string")) 调用它

编辑:如果您有 C++14,您可以执行以下操作(感谢 @MooingDuck 的启发)

#define BINDOVERLOADED(X) [](auto&& t) { return X(std::forward<decltype(t)>(t)); }
auto x = map(BINDOVERLOADED(f), make_tuple(3.14, "a string"));

http://coliru.stacked-crooked.com/a/439f958827de8cf2

【讨论】:

  • 我想我实际上会将Wrapper 包装在f 的宏中。
  • #define BINDOVERLOADED(X) struct{template&lt;class T&gt;auto operator()(T&amp;&amp;t)const-&gt;decltype(X(std::forward&lt;T&gt;(t)){return X(std::forward&lt;T&gt;(t));}}() 然后是map(BINDOVERLOADED(to_string),my_tuple);
  • @MookingDuck:这似乎不起作用有两个原因。 1) 我不能将结构声明为表达式的一部分,并且 2) 我不能声明本地结构的成员模板函数。不确定那是 gcc 还是标准目前所说的 ideone.com/XBFGMx
  • #define BINDOVERLOADED(X) [](auto&amp;&amp;t){return X(std::forward&lt;decltype(param)&gt;(t));} 用于 C++14? (有趣的是,这些将 types 也视为重载函数,BINDOVERLOADED(char)(42)
  • 我需要学习 C++14 :( 阅读:scottmeyers.blogspot.com/2013/05/… .......
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 2019-01-09
  • 1970-01-01
  • 1970-01-01
  • 2013-07-28
  • 2018-03-14
  • 1970-01-01
  • 2017-11-08
相关资源
最近更新 更多