我被指控重构旧代码并且偶然发现了这个案例:
void myClass::doStuff()
{
for( myIterator< Type1 > it( this->getDatabase() ); it; ++it )
{
do1( *it );
do2( *it );
do3( *it );
}
for( myIterator< Type2 > it( this->getDatabase() ); it; ++it )
{
do1( *it );
do2( *it );
do3( *it );
}
for( myIterator< Type3 > it( this->getDatabase() ); it; ++it )
{
do1( *it );
do2( *it );
do3( *it );
}
}
它显然很糟糕,因为我基本上复制了相同的代码3次,所以我决定使用这样的模板重构它:
template<class _type> void myClass::do123()
{
for( myIterator< _type > it( this->getDatabase() ); it; ++it )
{
do1( *it );
do2( *it );
do3( *it );
}
}
void myClass::doStuffBetter()
{
do123<Type1>();
do123<Type2>();
do123<Type3>();
}
还有其他更简单/更有效的方法来分解代码中的这种重复吗?
奖金问题:如果我的类型不是静态的,而是以可变参数模板给出,我将如何进行类似的处理?
答案 0 :(得分:1)
您可以使用boost::mpl::vector<>
作为类型列表,使用boost::mpl::for_each
来迭代这些类型:
#include <boost/mpl/vector.hpp>
#include <boost/mpl/for_each.hpp>
#include <iostream>
#include <typeinfo>
struct Type1 {};
struct Type2 {};
struct Type3 {};
template<class T>
struct Type
{
typedef T agrument_type;
};
int main(int ac, char**) {
using Types = boost::mpl::vector<Type1, Type2, Type3>;
boost::mpl::for_each<Types, Type<boost::mpl::_1> >([](auto type_wrapper) {
using Type = typename decltype(type_wrapper)::agrument_type;
// Place your code here.
std::cout << typeid(Type).name() << '\n';
});
}
输出:
5Type1
5Type2
5Type3
如果带有auto
的C ++ 14 lambda不可用,请使用以下功能对象而不是lambda函数:
struct TypeCallback
{
template<class TypeWrapper>
void operator()(TypeWrapper) {
using Type = typename TypeWrapper::agrument_type;
// Place your code here.
std::cout << typeid(Type).name() << '\n';
}
};
然后:
boost::mpl::for_each<Types, Type<boost::mpl::_1> >(TypeCallback{});
如果没有使用boost,只需创建一个迭代硬编码类型列表的函数:
boost::mpl::vector<>
答案 1 :(得分:1)
这是一个C ++ 14解决方案。
namespace notstd {
template<class T> struct tag_t { constexpr tag_t() {}; using type=T; };
template<class T> constexpr tag_t<T> tag{};
template<class Tag> using type_t = typename Tag::type;
template<class...Ts, class F>
void for_each_type(F&& f) {
using discard=int[];
(void)discard{ 0,(void(
f( tag<Ts> )
),0)...};
}
}
这是一些样板。
现在我们做:
void myClass::doStuffBetter()
{
notstd::for_each_type<Type1,Type2,Type2>(
[&](auto tag){
using type=notstd::type_t<decltype(tag)>;
for( myIterator<type> it( getDatabase() ); it; ++it )
{
do1( *it );
do2( *it );
do3( *it );
}
}
);
}
我们可以更进一步升级myIterator<_type>
,使得默认构造的实例比较等于一个过去的迭代器。
namespace notstd {
template<class It>
struct range_t {
It b, e;
It begin() const { return b; }
It end() const { return e; }
};
template<class It>
range_t<It> range( It s, It f = {} ) {
return {std::move(s), std::move(f)};
}
}
然后我们得到:
void myClass::doStuffBetter()
{
notstd::for_each_type<Type1,Type2,Type2>(
[&](auto tag){
using type=notstd::type_t<decltype(tag)>;
for( auto&& e : notstd::range( myIterator<type>( getDatabase() ) )
{
do1( e );
do2( e );
do3( e );
}
}
);
}
答案 2 :(得分:1)
我发现你的解决方案足够好了。
为了好玩,我提出以下doStuffBetter()
template <typename ... Types>
void myClass::doStuffBetter()
{
int unused[] { (do123<Types>(), 0)... };
(void)unused; // to avoid a warning
}
应该使用C ++ 11,我想这也可以回应你的奖金问题。