读书人

编写一个元函数,该如何处理

发布时间: 2012-03-09 16:54:57 作者: rapoo

编写一个元函数

C/C++ code
template<typename C, typename A, typename B>struct type_replace;

接受一个复合类型C作为第一个参数,并将其中的类型A替换为类型B

C/C++ code
typedef type_replace< void*, void, int > :: result_type t1; // int*typedef type_replace< int const* [10], int const, long > :: result_type t2; // long* [10]typedef type_replace< char& (*)(char&, const char*), char&, long > :: result_type t3;// long (*)(long, const char*)


c++ template metaprogramming 中的一道例题, 想了好久, 郁闷

[解决办法]
代码量还是不小的,如果不用boost库里已经现成的部分组件的话。
要之,就是T的所有可能复合类型也就T、T *、T []、 T &及一些对应的const版本,得穷举出来,特化处理。
[解决办法]
这个问题有意思,貌似没有简单易行的解法,临时写了一个比较基本的,涵盖不了所有情况,不过LZ列出的几种情况都能够处理了。
C/C++ code
 
#include <cstddef>

template <typename,typename> struct is_same { enum { value = false }; };
template <typename T> struct is_same <T, T> { enum { value = true }; };

template <bool, typename, typename> struct select;
template <typename T, typename U> struct select <true ,T,U> { typedef T type; };
template <typename T, typename U> struct select <false,T,U> { typedef U type; };

// General
template <typename T, typename X, typename Y>
struct replace { typedef typename select <is_same <T,X>::value,Y,T>::type type; };

// Simple composite
template <typename T, typename Y> struct replace <T&,T&,Y> { typedef Y type; };
template <typename T, typename Y> struct replace <T*,T*,Y> { typedef Y type; };
template <typename T, typename Y> struct replace <T[],T[],Y> { typedef Y type; };
template <typename T, typename Y, size_t S>
struct replace <T[S],T[S],Y> { typedef Y type; };

// Compound composite
template <typename T, typename X, typename Y>
struct replace <T&,X,Y>
{ typedef typename replace <T,X,Y>::type& type; };

template <typename T, typename X, typename Y>
struct replace <T*,X,Y>
{ typedef typename replace <T,X,Y>::type* type; };

template <typename T, typename X, typename Y>
struct replace <T[],X,Y>
{ typedef typename replace <T,X,Y>::type type [] ; };

template <typename T, typename X, typename Y, size_t size>
struct replace <T[size],X,Y>
{ typedef typename replace <T,X,Y>::type type [size]; };

// Functions
template <typename R, typename X, typename Y>
struct replace <R(),X,Y>
{ typedef typename replace <R,X,Y>::type (type) (); };

template <typename R, typename A1, typename X, typename Y>
struct replace <R(A1),X,Y>
{ typedef typename replace <R,X,Y>::type (type) (typename replace <A1,X,Y>::type); };

template <typename R, typename A1, typename A2, typename X, typename Y>
struct replace <R(A1,A2),X,Y>
{
typedef typename replace <R,X,Y>::type (type)
(typename replace <A1,X,Y>::type, typename replace <A2,X,Y>::type);
};

// Pointers to member functions
template <typename C, typename R, typename X, typename Y>
struct replace <R (C::*) (),X,Y>
{ typedef typename replace <R,X,Y>::type (replace <C,X,Y>::type :: * type) (); };



template <typename C, typename R, typename A1, typename X, typename Y>
struct replace <R (C::*) (A1),X,Y>
{
typedef typename replace <R,X,Y>::type (replace <C,X,Y>::type :: * type)
(typename replace <A1,X,Y>::type);
};

template <typename C, typename R, typename A1, typename A2, typename X, typename Y>
struct replace <R (C::*) (A1,A2),X,Y>
{
typedef typename replace <R,X,Y>::type (replace <C,X,Y>::type :: * type)
(typename replace <A1,X,Y>::type, typename replace <A2,X,Y>::type);
};

// Pointers to const member functions
template <typename C, typename R, typename X, typename Y>
struct replace <R (C::*) () const,X,Y>
{ typedef typename replace <R,X,Y>::type (replace <C,X,Y>::type :: * type) () const; };

template <typename C, typename R, typename A1, typename X, typename Y>
struct replace <R (C::*) (A1) const,X,Y>
{
typedef typename replace <R,X,Y>::type (replace <C,X,Y>::type :: * type)
(typename replace <A1,X,Y>::type) const;
};

template <typename C, typename R, typename A1, typename A2, typename X, typename Y>
struct replace <R (C::*) (A1,A2) const,X,Y>
{
typedef typename replace <R,X,Y>::type (replace <C,X,Y>::type :: * type)
(typename replace <A1,X,Y>::type, typename replace <A2,X,Y>::type) const;
};

// For member function tests
struct test1 { };
struct test2 { };

int main (int,char**)
{
// LZ's tests
static_assert(is_same <int*,
replace <void*,void,int>::type>::value,"");

static_assert(is_same <long*[10],
replace <int const*[10],int const,long>::type>::value,"");

static_assert(is_same <long,
replace <char&,char&,long>::type>::value,"");

static_assert(is_same <long(*)(long,const char*),
replace <char&(*)(char&,const char*),char&,long>::type>::value,"");

static_assert(is_same <long(*)(long(*)(long),const char*),
replace <char&(*)(char&(*)(char&),const char*),char&,long>::type>::value,"");

// Simple type
static_assert(is_same <int,
replace <char,char,int>::type>::value,"");
static_assert(is_same <int,
replace <char const,char const,int>::type>::value,"");
static_assert(is_same <int,
replace <char volatile,char volatile,int>::type>::value,"");
static_assert(is_same <int,
replace <char const volatile,char volatile const,int>::type>::value,"");

// Simple pointer type
static_assert(is_same <int,
replace <char*,char*,int>::type>::value,"");
static_assert(is_same <int,
replace <char const*,char const*,int>::type>::value,"");
static_assert(is_same <int,
replace <char volatile*,char volatile*,int>::type>::value,"");
static_assert(is_same <int,
replace <char const volatile*,char volatile const*,int>::type>::value,"");

// Simple reference type
static_assert(is_same <int,
replace <char&,char&,int>::type>::value,"");
static_assert(is_same <int,
replace <char const&,char const&,int>::type>::value,"");
static_assert(is_same <int,
replace <char volatile&,char volatile&,int>::type>::value,"");
static_assert(is_same <int,
replace <char const volatile&,char volatile const&,int>::type>::value,"");



// Simple dynamic array type
static_assert(is_same <int,
replace <char[],char[],int>::type>::value,"");
static_assert(is_same <int,
replace <char const[],char const[],int>::type>::value,"");
static_assert(is_same <int,
replace <char volatile[],char volatile[],int>::type>::value,"");
static_assert(is_same <int,
replace <char const volatile[],char volatile const[],int>::type>::value,"");

// Simple static array type
static_assert(is_same <int,
replace <char[10],char[10],int>::type>::value,"");
static_assert(is_same <int,
replace <char const[10],char const[10],int>::type>::value,"");
static_assert(is_same <int,
replace <char volatile[10],char volatile[10],int>::type>::value,"");
static_assert(is_same <int,
replace <char const volatile[10],char volatile const[10],int>::type>::value,"");

// Composite pointer type
static_assert(is_same <int*,
replace <char*,char,int>::type>::value,"");
static_assert(is_same <int*,
replace <char const*,char const,int>::type>::value,"");
static_assert(is_same <int*,
replace <char volatile*,char volatile,int>::type>::value,"");
static_assert(is_same <int*,
replace <char const volatile*,char volatile const,int>::type>::value,"");

// Composite reference type
static_assert(is_same <int&,
replace <char&,char,int>::type>::value,"");
static_assert(is_same <int&,
replace <char const&,char const,int>::type>::value,"");
static_assert(is_same <int&,
replace <char volatile&,char volatile,int>::type>::value,"");
static_assert(is_same <int&,
replace <char const volatile&,char volatile const,int>::type>::value,"");

// Composite dynamic array type
static_assert(is_same <int[],
replace <char[],char,int>::type>::value,"");
static_assert(is_same <int[],
replace <char const[],char const,int>::type>::value,"");
static_assert(is_same <int[],
replace <char volatile[],char volatile,int>::type>::value,"");
static_assert(is_same <int[],
replace <char const volatile[],char volatile const,int>::type>::value,"");

// Composite static array type
static_assert(is_same <int[10],
replace <char[10],char,int>::type>::value,"");
static_assert(is_same <int[10],
replace <char const[10],char const,int>::type>::value,"");
static_assert(is_same <int[10],
replace <char volatile[10],char volatile,int>::type>::value,"");
static_assert(is_same <int[10],
replace <char const volatile[10],char volatile const,int>::type>::value,"");

// Functions
static_assert(is_same <int(),
replace <char(),char,int>::type>::value,"");
static_assert(is_same <int(int),
replace <char(char),char,int>::type>::value,"");
static_assert(is_same <int(int*,int&),
replace <char(char*,char&),char,int>::type>::value,"");

// Function pointers
static_assert(is_same <int(*)(),
replace <char(*)(),char,int>::type>::value,"");
static_assert(is_same <int(*)(int),
replace <char(*)(char),char,int>::type>::value,"");
static_assert(is_same <int(*)(int*,int&),


replace <char(*)(char*,char&),char,int>::type>::value,"");

// Function references
static_assert(is_same <int(&)(),
replace <char(&)(),char,int>::type>::value,"");
static_assert(is_same <int(&)(int),
replace <char(&)(char),char,int>::type>::value,"");
static_assert(is_same <int(&)(int*,int&),
replace <char(&)(char*,char&),char,int>::type>::value,"");

return 0;
}


其中的static_assert是C++0x的东西,LZ可以不必理会,这里的用途就是检查一下两个类别一样。
[解决办法]
写了一下,发现比预想的难,不过最后代码到比预想的少。
当然也没有覆盖所有的情况。
在vc7.1上测试,能处理楼主提出的几种情况。
理论上说也可以处理在这几种情况的任意组合。
C/C++ code
template<typename C, typename A, typename B, typename D>struct replace_aux{    typedef D result_type;};template<typename A, typename B, typename D>struct replace_aux<A, A, B, D>{    typedef B result_type;};template<typename C, typename A, typename B>struct type_replace{    typedef typename replace_aux<C, A, B, C>::result_type result_type;};template<typename C, typename A, typename B>struct type_replace<C*, A, B>{    typedef typename type_replace<C, A, B>::result_type replaced_type;    typedef replaced_type* composited_type;    typedef typename replace_aux<C*, A, B, composited_type>::result_type result_type;};template<typename C, typename A, typename B>struct type_replace<C&, A, B>{    typedef typename type_replace<C, A, B>::result_type replaced_type;    typedef replaced_type& composited_type;    typedef typename replace_aux<C&, A, B, composited_type>::result_type result_type;};template<typename C, typename A, typename B>struct type_replace<C const, A, B>{    typedef typename type_replace<C, A, B>::result_type replaced_type;    typedef replaced_type const composited_type;    typedef typename replace_aux<C const, A, B, composited_type>::result_type result_type;};template<int size, typename C, typename A, typename B>struct type_replace<C[size], A, B>{    typedef typename type_replace<C, A, B>::result_type replaced_type;    typedef replaced_type composited_type[size];    typedef typename replace_aux<C[size], A, B, composited_type>::result_type result_type;};template<typename R, typename A, typename B>struct type_replace<R (*)(), A, B>{    typedef typename type_replace<R, A, B>::result_type ret_type;    typedef ret_type (*composited_type)();    typedef typename replace_aux<R (*)(), A, B, composited_type>::result_type result_type;};template<typename R, typename P, typename A, typename B>struct type_replace<R (*)(P), A, B>{    typedef typename type_replace<R, A, B>::result_type ret_type;    typedef typename type_replace<P, A, B>::result_type param_type;    typedef ret_type (*composited_type)(param_type);    typedef typename replace_aux<R (*)(P), A, B, composited_type>::result_type result_type;};template<typename R, typename P1, typename P2, typename A, typename B>struct type_replace<R (*)(P1, P2), A, B>{    typedef typename type_replace<R, A, B>::result_type ret_type;    typedef typename type_replace<P1, A, B>::result_type param1_type;    typedef typename type_replace<P2, A, B>::result_type param2_type;    typedef ret_type (*composited_type)(param1_type, param2_type);    typedef typename replace_aux<R (*)(P1, P2), A, B, composited_type>::result_type result_type;};
[解决办法]
C/C++ code
//TypeReplace4Templ.hxx#pragma oncetemplate<typename C, typename A, typename B,int _Is_SuperT>struct TypeReplaceWrapper;template<template <typename> class Class,typename A, typename B,typename T1>struct TypeReplaceWrapper<Class<T1> ,A,B,0>{    RESUALT_TYPE_DEF(T1);    typedef Class<T_T1> result_type;};template<template <typename,typename> class Class,typename A, typename B,typename T1,typename T2>struct TypeReplaceWrapper<Class<T1,T2> ,A,B,0>{    RESUALT_TYPE_DEF(T1);    RESUALT_TYPE_DEF(T2);    typedef Class<T_T1,T_T2> result_type;};template<template <typename,typename,typename> class Class,typename A, typename B,typename T1,typename T2,typename T3>struct TypeReplaceWrapper<Class<T1,T2,T3> ,A,B,0>{    RESUALT_TYPE_DEF(T1);    RESUALT_TYPE_DEF(T2);    RESUALT_TYPE_DEF(T3);    typedef Class<T_T1,T_T2,T_T3> result_type;};template<template <typename,typename,typename,typename> class Class,typename A, typename B,typename T1,typename T2,typename T3,typename T4>struct TypeReplaceWrapper<Class<T1,T2,T3,T4> ,A,B,0>{    RESUALT_TYPE_DEF(T1);    RESUALT_TYPE_DEF(T2);    RESUALT_TYPE_DEF(T3);    RESUALT_TYPE_DEF(T4);    typedef Class<T_T1,T_T2,T_T3,T_T4> result_type;}; 

读书人网 >C++

热点推荐