我可以分离编译时策略的创建和使用位置吗?
Can I separate creation and usage locations of compile-time strategies?
#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子句:
TypeClass SubAlgorithm = runtime_flag : SubAlgorithm1 ? SubAlgorithm2;
SubAlgorithm sub_algorithm;
Algorithm(sub_algorithm, stuff);
有没有类似的方法?或者使用某种完全不同的模式(但不是运行时多态性虚拟函数)来解决这个问题?
注:在我的应用中,算法有几个子算法作为参数,子算法也有类似的结构。此外,一些子算法具有不同的创建接口。对于运行时多态性,我可以使用一种工厂模式,整个事情看起来很好(http://ideone.com/YAYafr),但我真的不能在这里使用虚函数。
P.P.S.我怀疑问题措辞反映了我在代码中实际问的问题,所以我很乐意得到任何建议。
是。我把这种技术称为"魔法开关"。
创建算法的std::tuple
。您创建了一个模板函数,该函数将被传递其中一个算法。
如果你愿意,你可以通过完全变分转发添加其他参数。
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 );
}
}
在伪代码中。将Max==0专门化为只返回false,并且您可能必须将其设置为函子,以便您可以部分专门化。
作为缺点,传入的函子写起来很烦人。
另一种变化是使用元工厂(嗯,是元编程类型工厂?也许它是一个元映射。嗯,等等。)
#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
数组。
有一个virtual
调用开销,但是它发生在顶层。
您应该使用一个接口,同时使用SubAlgorithm1和SubAlgorithm2(您需要更好的名称)实现该接口。可以根据runtime_flag创建任意一个类的对象
相关文章:
- 创建一个类来访问和指定向量类型,并构建一个获取位置并为其分配区域的类
- glfw 在创建之前/创建时实例化窗口位置
- 更改球体的位置而不重新创建球体
- 创建 2D 数组0xCCCCCCCC访问冲突写入位置
- 创建一个函数以在给定位置将元素插入到列表中
- 如何正确删除一行控件并在该位置动态创建一个新控件
- 尝试在自定义 QT 创建器文本编辑器中创建查找和替换循环.我似乎无法设置光标位置
- unordered_map emplace-如何在适当的位置创建对象
- 创建相对于世界位置而不是屏幕位置的形状
- 在数组中创建位置层次结构
- 尝试创建结构对象,在位置0x3FE00000中创建访问冲突写入错误
- 应删除传递参数时创建对象的位置
- 使用新的位置来创建静态常量指针,指向静态内存缓冲区
- 创建一个从前缀到C 中字符位置的新字符串
- 我创建的c++istream对象和cin之间的区别在哪里,它在库中的可见位置在哪里
- 创建新数组时写入位置时发生访问冲突
- 在磁盘C 上的特定位置中创建队列
- 类在同一内存位置创建另一个类的多个对象(C++)
- c++初始化器不断地在同一内存位置创建新对象
- 我们可以在内存中的指定位置创建一个类类型的实例吗