【问题标题】:Generalizing for_each over a tuple to accept a variable number of arguments在元组上泛化 for_each 以接受可变数量的参数
【发布时间】:2011-04-12 19:21:47
【问题描述】:

目前,我有:

template <unsigned I,
          unsigned N,
          typename Tuple,
          typename UnaryFunction>
struct for_;

template <unsigned N, typename Tuple, typename UnaryFunction>
struct for_<N, N, Tuple, UnaryFunction> {
  static
  void call(const Tuple&, UnaryFunction) {}
};

template <unsigned I,
          unsigned N,
          typename Tuple,
          typename UnaryFunction>
struct for_ {
  static
  void call(Tuple&& x, UnaryFunction f) {
    f(get<I>(x));
    for_<I + 1, N, Tuple, UnaryFunction>::call(std::forward<Tuple>(x), f);
  }
};

template <typename Tuple, typename UnaryFunction>
inline
void for_each(Tuple&& x, UnaryFunction f) {
  for_<0,
    tuple_size<
      typename std::remove_const<
        typename std::remove_reference<Tuple>::type
      >::type
    >::value,
    Tuple,
    UnaryFunction>::call(std::forward<Tuple>(x), f);
}

是否可以通过可变参数模板来概括这一点,以采用任意数量的元组参数?

编辑:

以下是我将如何使用我无法定义的内容:

if (i != e) {
  std::array<Tuple, 2> x;
  std::get<0>(x) = *i;
  std::get<1>(x) = *i;
  ++i;
  std::for_each (i, e, [&x](const Tuple& y) {
    for_each(std::get<0>(x), y, assign_if(std::less));
    for_each(std::get<1>(x), y, assign_if(std::greater));
  });
}

编辑:改为使用右值引用和 std::forward

【问题讨论】:

  • 这是如何工作的,考虑到元组是异构的,但每个元素只有一个 UnaryFunction 重载?
  • 它要求元组是同质的——我使用元组来表示几何点(元组)。 array 也可以工作(我相信它支持元组接口) - 重要的部分是编译时 get (与运行时迭代器相比)。这部分是为了在不影响编译时检查的情况下将用途推广到其他维度(array 等)。
  • 这很容易实现,但前提是您使用适当的仿函数与 lambda。 C++11 lambda 本质上是单态的;如果您想要高效的多态 lambda,请考虑使用 boost.phoenix
  • 我能够使用 map_each(UnaryFunction, Head&&, Tail&&...) 使其工作,并计划在必要的 24 小时后提交此文件,除非其他人可以提出使用 UnaryFunction 作为解决方案最终参数类型。
  • @ScootyPuff:仅供参考,§14.8.2.5/10 说函数参数包只能出现在参数声明列表的末尾。所以,如果你需要的是可变参数函数模板,UnaryFunction 可能无法成为最终参数。

标签: c++ c++11 variadic-functions variadic-templates


【解决方案1】:

我不确定它是否符合您的预期,但我会发布 - 也许有人会觉得它有帮助。

namespace std {
    template<int I, class Tuple, typename F> struct for_each_impl {
        static void for_each(const Tuple& t, F f) {
            for_each_impl<I - 1, Tuple, F>::for_each(t, f);
            f(get<I>(t));
        }
    };
    template<class Tuple, typename F> struct for_each_impl<0, Tuple, F> {
        static void for_each(const Tuple& t, F f) {
            f(get<0>(t));
        }
    };
    template<class Tuple, typename F>
    F for_each(const Tuple& t, F f) {
        for_each_impl<tuple_size<Tuple>::value - 1, Tuple, F>::for_each(t, f);
        return f;
    }
}

函子:

struct call_tuple_item {
    template<typename T>
    void operator()(T a) {
        std::cout << "call_tuple_item: " << a << std::endl;
    }
};

主要功能:

std::tuple<float, const char*> t1(3.14, "helloworld");
std::for_each(t1, call_tuple_item());

【讨论】:

    【解决方案2】:

    您可以在此处查看我的答案以获取有关扩展元组的提示

    How do I expand a tuple into variadic template function's arguments?

    【讨论】:

    • 元组打包/解包是否会产生任何开销?我假设一个体面的编译器,不。我的计划是编写一个类似“zip”(hoogle zip)的函数来执行压缩,然后使用与您类似的代码来解压缩并应用该函数。
    • 我认为不会,一个好的编译器会将所有内容展开并压缩为紧凑形式,就像您手动编写一样
    • 我唯一关心的是元组的类型 - 我假设我希望它是 tuple&lt;Args&amp;...&gt; 或类似的,以确保没有复制构造函数等(即使实际的元组type 在运行时可能不存在,我假设某些对象的构造函数/析构函数/赋值运算符可能具有无法省略的副作用)。
    【解决方案3】:

    请参阅下文,了解我将使用的map(UnaryFunction, Tuple&amp;&amp;...) 实现,以及我一直在弄乱的代码,以使其完全按照我的意愿工作(for_auxlast 等)。

    #include <array>
    #include <iostream>
    #include <tuple>
    
    namespace detail {
    
      struct static_ {
      private:
        static_() = delete;
        static_(const static_&) = delete;
        static_& operator=(const static_&) = delete;
      };
    
      template <unsigned... Args>
      struct max;
    
      template <unsigned Head, unsigned... Tail>
      struct max<Head, Tail...>: private static_ {
        static const unsigned value = Head > max<Tail...>::value
          ? Head
          : max<Tail...>::value;
      };
    
      template <>
      struct max<>: private static_ {
        static const unsigned value = 0;
      };
    
      template <unsigned... Args>
      struct min;
    
      template <unsigned Head, unsigned... Tail>
      struct min<Head, Tail...>: private static_ {
        static const unsigned value = Head < min<Tail...>::value
          ? Head
          : min<Tail...>::value;
      };
    
      template <>
      struct min<>: private static_ {
        static const unsigned value = 0;
      };
    
      template <typename... Args>
      struct for_aux;
    
      template <typename A, typename B>
      struct for_aux<A, B>: private static_ {
        static
        void call(A&& a, B b) {
          b(std::forward(a));
        }
      };
    
      template <typename A, typename B, typename C>
      struct for_aux<A, B, C>: private static_ {
        static
        void call(A&& a, B&& b, C c) {
          c(std::forward(a), std::forward(b));
        }
      };
    
      template <typename A, typename B, typename C, typename D>
      struct for_aux<A, B, C, D>: private static_ {
        static
        void call(A&& a, B&& b, C&& c, D d) {
          d(std::forward(a), std::forward(b), std::forward(c));
        }
      };
    
      // template <typename Head, typename... Tail>
      // struct for_aux: private static_ {
      //   static
      //   void call(Tail&&... x, Head f) {
      //     f(std::forward(x)...);
      //   }
      // };
    
      template <typename... Args>
      struct last;
    
      template <typename X>
      struct last<X>: private static_ {
        typedef X type;
      };
    
      template <typename Head, typename... Tail>
      struct last<Head, Tail...>: private static_ {
        typedef typename last<Tail...>::type type;
      };
    
      template <unsigned I,
                unsigned N,
                typename UnaryFunction,
                typename... Tuples>
      struct map;
    
      template <unsigned N, typename UnaryFunction, typename... Tuples>
      struct map<N, N, UnaryFunction, Tuples...>: private static_ {
        static
        void call(UnaryFunction, const Tuples&...) {}
      };
    
      template <unsigned I,
                unsigned N,
                typename UnaryFunction,
                typename... Tuples>
      struct map: private static_ {
        static
        void call(UnaryFunction f, Tuples&&... x) {
          f(std::get<I>(std::forward<Tuples>(x))...);
          map<I + 1,
            N,
            UnaryFunction,
            Tuples...>::call(f, std::forward<Tuples>(x)...);
        }
      };
    
      template <typename Tuple>
      struct tuple_size: private static_ {
        enum {
          value = std::tuple_size<
            typename std::remove_const<
              typename std::remove_reference<Tuple>::type
            >::type
          >::value
        };
      };
    
    }
    
    template <typename UnaryFunction, typename... Tuples>
    inline
    void map(UnaryFunction f, Tuples&&... x) {
      detail::map<0,
        detail::max<
          detail::tuple_size<Tuples>::value...
        >::value,
        UnaryFunction,
        Tuples...
      >::call(f, std::forward<Tuples>(x)...);
    }
    
    using namespace std;
    
    struct f {
      template <typename T, typename U>
      void operator()(const T& i, const U& j) {
        cout << i << " " << j << endl;
      }
    };
    
    int main() {
      const array<int, 2> x = {{2}};
      const tuple<double, char> y(1.1, 'a');
      map(f(), x, y);
    }
    

    【讨论】:

      猜你喜欢
      • 2016-08-22
      • 2010-12-09
      • 1970-01-01
      • 2011-08-08
      • 1970-01-01
      • 2023-03-09
      • 1970-01-01
      • 2021-03-26
      • 1970-01-01
      相关资源
      最近更新 更多