我可以分隔编译时策略的创建和使用位置吗? [英] Can I separate creation and usage locations of compile-time strategies?

查看:115
本文介绍了我可以分隔编译时策略的创建和使用位置吗?的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

#include <iostream>
#include <vector>
#include <algorithm>
#include <sstream>

using namespace std;

struct SubAlgorithm1 { void operator () (int /*i*/) { cout << "1" << endl; } };
struct SubAlgorithm2 { void operator () (int /*i*/) { cout << "2" << endl; } };

template<typename SubAlgorithm, typename Collection>
void Alrogirthm(SubAlgorithm& f, Collection& stuff) {
  // In my code f is invoked ~ 1e9 times (it's a loop that is executed ~
  // 1e6 times, and stuff.size() is ~1000). The application spends ~90% of
  // it's time in this function, so I do not want any virtual function
  // calls to slow down my number-crunching.
  for (int i = 0; i < 1; ++i) for_each(stuff.begin(), stuff.end(), f);
}

int main(int , char**) {
  vector<int> stuff;
  stuff.push_back(1);

  bool runtime_flag = true; // let's pretend it was read from config
  if (runtime_flag) {
    typedef SubAlgorithm1 SubAlgorithm;

    SubAlgorithm sub_algorithm;
    Alrogirthm(sub_algorithm, stuff);
  }
  else {
    typedef SubAlgorithm2 SubAlgorithm;

    SubAlgorithm sub_algorithm;
    Alrogirthm(sub_algorithm, stuff);
  }

  return 0;
}

我真的很喜欢写上述if子句: p>

What I would really love to write instead of the if clause above:

TypeClass SubAlgorithm = runtime_flag : SubAlgorithm1 ? SubAlgorithm2;
SubAlgorithm sub_algorithm;
Algorithm(sub_algorithm, stuff);

有什么办法做类似的事吗?或者某种完全其他的模式(但不是运行时多态性\ virtual functions)来解决这个问题?

Is there any way of doing something similar? Or some kind of completely other pattern (but not run-time polymorphism\virtual functions) to solve that issue?

在我的应用程序中,算法有几个SubAlgorithms作为参数和SubAlgorithms也有类似的结构。此外,一些子算法具有不同的创建界面。使用运行时多态性我可以使用工厂模式,整个事情看起来不错( http://ideone.com/YAYafr ),但我真的不能在这里使用虚拟函数。

P.S. In my application Algorithm has several SubAlgorithms as parameters and SubAlgorithms as well have similar structure. Moreover some SubAlgorithms have different creation interface. With run-time polymorphism I can use kind of Factory pattern and the whole thing looks nice (http://ideone.com/YAYafr), but I really cannot use virtual functions here.

PPS我怀疑这个问题反映了我在代码中的实际问题,所以我很乐意得到任何建议。

P.P.S. I doubt the question phrasing reflects what I actually ask in the code, so I'd be happy to get any suggestions.

推荐答案

是。

你创建一个 std :: tuple 的算法。

如果需要,您可以通过完美的变量转发来添加其他参数。

You can add other arguments via perfect variardic forwarding if you want.

template<size_t Max, typename...Ts, typename Func>
bool magic_switch( int n, Func&& f,  std::tuple<Ts...> const & pick ) {
  if( n==Max-1 ) {
    f(std::get<Max-1>(pick));
    return true;
  } else {
    return magic_switch<Max-1>( n, std::forward<Func>(f), pick );
  }
}

Specialize Max == 0只返回false,你可能必须将它作为一个函数,以便你可以部分专门化。

In pseudo code. Specialize Max==0 to just return false, and you might have to make it a functor so you can partial specialize.

传递的函数恼人地写,

The passed in functor is annoying to write, as a downside.

另一个变化是使用元工厂(好,元程序设计类型的工厂,也许它是一个元映射,嗯,无论如何。)

Another variation is to use a meta-factory (well, a meta programming type factory? Maybe it is a meta-map. Well, whatever.)

#include <iostream>
#include <tuple>
#include <vector>
#include <utility>
#include <cstddef>
#include <functional>
#include <array>
#include <iostream>

// metaprogramming boilerplate:
template<template<typename>class Factory, typename SourceTuple>
struct tuple_map;
template<template<typename>class Factory, template<typename...>class L, typename... SourceTypes>
struct tuple_map<Factory, L<SourceTypes...>> {
  typedef L< Factory<SourceTypes>... > type;
};
template<template<typename>class Factory, typename SourceTuple>
using MapTuple = typename tuple_map<Factory, SourceTuple>::type;
template<std::size_t...> struct seq {};
template<std::size_t max, std::size_t... s>
struct make_seq: make_seq<max-1, max-1, s...> {};
template<std::size_t... s>
struct make_seq<0, s...> {
  typedef seq<s...> type;
};
template<std::size_t max>
using MakeSeq = typename make_seq<max>::type;

// neat little class that lets you type-erase the contents of a tuple,
// and turn it into a uniform array:
template<typename SourceTuple, typename DestType>
struct TupleToArray;
template<template<typename...>class L, typename... Ts, typename DestType>
struct TupleToArray<L<Ts...>, DestType> {
  template<std::size_t... Index>
  std::array< DestType, sizeof...(Ts) > operator()( L<Ts...> const& src, seq<Index...> ) const {
    std::array< DestType, sizeof...(Ts) > retval{ DestType( std::get<Index>(src) )... };
    return retval;
  }

  std::array< DestType, sizeof...(Ts) > operator()( L<Ts...> const& src ) const {
    return (*this)( src, MakeSeq<sizeof...(Ts)>() );
  }
};
template< typename DestType, typename SourceTuple >
auto DoTupleToArray( SourceTuple const& src )
  -> decltype( TupleToArray<SourceTuple, DestType>()( src ) )
{
  return TupleToArray<SourceTuple, DestType>()( src );
}

// Code from here on is actually specific to this problem:
struct SubAlgo { int operator()(int x) const { return x; } };
struct SubAlgo2 { int operator()(int x) const { return x+1; } };

template<typename Sub>
struct FullAlgo {
  void operator()( std::vector<int>& v ) const {
    for( auto& x:v )
      x = Sub()( x );
  }
};

// a bit messy, but I think I could clean it up:
typedef std::tuple< SubAlgo, SubAlgo2 > subAlgos;
MapTuple< FullAlgo, subAlgos > fullAlgos;
typedef std::function< void(std::vector<int>&) > funcType;
std::array< funcType, 2 > fullAlgoArray =
  DoTupleToArray< funcType >( fullAlgos );

int main() {
  std::vector<int> test{1,2,3};
  fullAlgoArray[0]( test );
  for (auto&& x: test)
    std::cout << x;
  std::cout << "\n";
  fullAlgoArray[1]( test );
  for (auto&& x: test)
    std::cout << x;
  std::cout << "\n";
}

这是很多样板,但我刚刚做的是允许你采用无状态子算法并将其插入到您的完整算法中一次一个元素,然后键入擦除结果的完整算法并将其存储在 std :: function 数组。

which is lots of boilerplate, but what I've just done is allowed you to take your stateless sub algorithm and plug it into your full algorithm one element at a time, then type-erase the resulting full algorithm and store it in a std::function array.

有一个虚拟调用开销,但它出现在顶层。

There is a virtual call overhead, but it occurs at the top level.

这篇关于我可以分隔编译时策略的创建和使用位置吗?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
相关文章
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆