首先,这样写:
template<typename T, typename U>
U convert( T const& src );
因为其他一切都应该用模板元编程来编写。这样做的好处是,如果需要,您可以专业化您的convert<int, double>
和您的。convert<std::string, int>
接下来,写这个:
template<typename T, typename U>
void convert_buffer( T const* src, U* dest, size_t n );
convert
它只是在循环中调用上面。我把它分成两个函数,因为可能不统一的代码进入convert
,并且调用一个其主体可见的函数基本上是零开销。
然后写这个:
typedef void(*blind_converter)(void const*, void*, size_t);
template<typename T, typename U>
void convert_blind_buffer( void const* src, void* dest, size_t n ) {
return convert_buffer( reinterpret_cast<T const*>(src), reinterpret_cast<U*>(dest), n );
}
它封装了转换,并且不需要您进行理论上无效的指针类型转换。它是“转换盲”缓冲区 - 盲,因为它需要void*
s。
接下来,我们不想手动维护您的 NxN 数组。用于存储您的有序类型列表的类型:
template<typename... Ts>
struct type_list {};
然后我们编写一些元编程来构建 NxN 数组:
template<typename Src, typename DestList>
struct make_convert_one_way;
template<typename Src, typename... Ds>
struct make_convert_one_way< Src, type_list<Ds...> > {
std::array< blind_converter, sizeof...(Ds) > operator()() const {
return { convert_blind_buffer< Src, Ds >... };
}
};
template<typename list>
struct make_convert_array;
template<typename... Ts>
struct make_convert_array< type_list<Ts...> > {
std::array< std::array<blind_converter, sizeof...(Ts) >, sizeof...(Ts) > operator()() const {
return { make_convert_one_way< Ts, type_list<Ts...> >... };
}
};
typedef type_list< int, char, double > my_list;
auto convert_array = make_convert_array<my_list>()();
或类似的规定。
如果您的 source 和 dest 类型不统一,则必须将上面的内容修改为采用两个type_list
s,但从根本上来说并没有什么困难。
下一个有用的东西是从一个类型映射到上述数组中的索引的能力,因为维护它应该是编译器的工作。
template<typename T, typename List, typename=void>
struct index_of;
template<typename T, typename T0, typename... Ts>
struct index_of<T, type_list<T0, Ts...>, typename std::enable_if<
std::is_same<T, T0>::value
>::type >: std::integral_constant< std::size_t, 0 > {};
template<typename T, typename T0, typename... Ts>
struct index_of<T, type_list<T0, Ts...>, typename std::enable_if<
!std::is_same<T, T0>::value
>::type >: std::integral_constant< std::size_t, index_of<T, type_list<Ts...>::value+1 > {};
它可以让你这样做:
static_assert( index_of< int, my_list >::value == 0, "all is well!" );
现在,你可能想用某种类型的敷料把它包起来。策略可能如下所示:
template<typename List>
struct EnumDressing;
template<typename... Ts>
struct EnumDressing<type_list<Ts...>> {
enum type {
e_begin = 0,
e_end = sizeof...(Ts),
};
template<typename T>
static constexpr type value() {
return static_cast<type>( index_of<T, type_list<Ts...> >::value );
}
};
其中我们有EnumDressing<my_list>::type
一个表示类型整数名称的 anenum
类型,它的值可以通过EnumDressing<my_list>::value<int>()
. typedef
自然地你用s清理它:
typedef EnumDressing<my_list> Types;
typedef Types::type eType;
struct typed_array {
eType type;
void* buff;
size_t n;
};
void do_convert( typed_array src, typed_array dst) {
Assert(src.n == dst.n);
convert_array[ src.type ][ dst.type ]( src.buff, dst.buff, std::min( src.n, dst.n ) );
}
template<typename T, size_t N>
typed_array make_typed_array( T (&arr)[N] ) {
return { Types::value<T>(), reinterpret_cast<void*>( &arr[0] ), N };
}
int main() {
double d[100];
int i[100];
do_convert( make_typed_array( d ), make_typed_array( i ) );
}
自然的实际用例将创建与使用分开typed_array
。