我正在尝试创建一个模板"AutoClass“,它创建一个具有任意成员集的任意类,例如:
AutoClass<int,int,double,double> a;
a.set(1,1);
a.set(0,2);
a.set(3,99.7);
std::cout << "Hello world! " << a.get(0) << " " << a.get(1) << " " << a.get(3) << std::endl;到目前为止,我已经有了一个具有工作“AutoClass”成员的set:
class nothing {};
template < typename T1 = nothing, typename T2 = nothing, typename T3 = nothing,
typename T4 = nothing, typename T5 = nothing, typename T6 = nothing>
class AutoClass;
template <>
class AutoClass<nothing, nothing, nothing,
nothing, nothing, nothing>
{
public:
template <typename U> void set(int n,U v){}
};
template < typename T1, typename T2, typename T3,
typename T4, typename T5, typename T6>
class AutoClass: AutoClass<T2,T3,T4,T5,T6>
{
public:
T1 V;
template <typename U> void set(int n,U v)
{
if (n <= 0)
V = v;
else
AutoClass<T2,T3,T4,T5,T6>::set(n-1,v);
}
};我开始在实现相应的"get“时遇到问题。这种方法不能编译:
template < typename T1, typename T2, typename T3,
typename T4, typename T5, typename T6>
class AutoClass: AutoClass<T2,T3,T4,T5,T6>
{
public:
T1 V;
template <typename U> void set(int n,U v)
{
if (n <= 0)
V = v;
else
AutoClass<T2,T3,T4,T5,T6>::set(n-1,v);
}
template <typename W> W get(int n)
{
if (n <= 0)
return V;
else
return AutoClass<T2,T3,T4,T5,T6>::get(n-1);
}
template <> T1 get(int n)
{
if (n <= 0)
return V;
else
return AutoClass<T2,T3,T4,T5,T6>::get(n-1);
}
};此外,我似乎需要为<nothing, nothing, nothing, nothing, nothing, nothing>专门化实现get。有没有办法解决这个问题?
发布于 2010-03-27 02:43:24
首先,我更喜欢Boost.Fusion而不是Boost.Tuple,因为我认为它支持模板元编程和运行时算法的更好的混合。
举个例子,我想向你们展示一个小奇迹:
struct Name {}; extern const Name name;
struct GivenName {}; extern const GivenName givenName;
struct Age {}; extern const Age age;
class Person
{
public:
template <class T>
struct value
{
typedef typename boost::fusion::result_of::at_key<data_type const,T>::type type;
};
template <class T>
struct has
{
typedef typename boost::fusion::result_of::has_key<data_type,T>::type type;
};
template <class T>
typename value<T>::type
get(T) { return boost::fusion::at_key<T>(mData); }
template <class T>
Person& set(T, typename value<T>::type v)
{
boost::fusion::at_key<T>(mData) = v; return *this;
};
private:
typedef boost::fusion::map <
std::pair<Name, std::string>,
std::pair<GivenName, std::string>,
std::pair<Age, unsigned short>
> data_type;
data_type mData;
};使用它真的很有趣:
Person p;
p.set(name, "Rabbit").set(givenName, "Roger").set(age, 22);嗯,我自己更喜欢按类索引而不是按索引,因为我既可以传达含义,也可以添加类型检查;)
发布于 2010-03-27 01:26:58
我可以推荐使用Boost库的大量(且经过良好测试且跨平台的)模板-magicky类吗?听起来你要找的是boost::tuple。任何时候你都可以不用写自己的代码-尤其是在使用模板的复杂情况下-你应该使用别人的代码。
发布于 2010-03-27 02:28:58
正如其他人所提到的,通过重用Boost或其他地方的现有实现,您可能能够得到您想要的东西。
如果你想做一些使用这些工具无法完成的事情,或者你很好奇:
一种简单的方法是,为了方便使用MPL,可能如下所示:
template<class Types, size_t N> struct holder
// recursively derive from holder types:
: holder<Types, N-1>
{
typename boost::mpl::at_c<Types,N>::type value;
};
// specialization that terminates the recursive derivation:
template<class Types> struct holder<Types,0> {
typename boost::mpl::at_c<Types,0>::type value;
};
template<class Types>
class AutoClass
// recursively derive from holder types:
: holder<Types, boost::mpl::size<Types>::value-1>
{
enum { n = boost::mpl::size<Types>::value };
public:
template<size_t N, class U> void set(const U& u) {
// index check at compile time:
BOOST_STATIC_ASSERT((N < n));
// cast to responsible holder base:
static_cast<holder<Types,N>*>(this)->value = u;
}
template<size_t N> typename boost::mpl::at_c<Types,N>::type get() const {
// index check at compile time:
BOOST_STATIC_ASSERT((N < n));
// cast to responsible holder base:
return static_cast<const holder<Types,N>*>(this)->value;
}
};用法:
typedef boost::mpl::vector<int,std::string> Types;
AutoClass<Types> a;
a.set<0>(42);
assert(a.get<0>() == 42);
a.set<1>("abcde");
assert(a.get<1>() == "abcde");请记住,为了方便最终用户,仍然可以使用伪可变模板对其进行包装。
https://stackoverflow.com/questions/2525277
复制相似问题