注意:我知道我在这里做的很多事情在C ++ 11中会更容易,但我无法在我的项目中使用它。
我正在制作内容管理系统。基本要求是:
IntHolder
可以包含vector<int>
,FloatAndBoolHolder
可以包含vector<float>
和vector<bool>
,依此类推。get<>()
方法。 get<>()
的模板参数是一种类型。如果内容持有者具有该类型的向量,则get<>()
必须从该向量返回一个值,否则对get<>()
的调用必须生成编译器错误。例如。如果我有一个IntHolder
对象,那么在其上调用get<int>()
将从其向量返回int
,但在其上调用get<float>()
会产生编译错误。我设法提出了解决所有这些问题的解决方案。警告,模板递归:
#include <iostream>
#include <vector>
#include <string>
using namespace std;
int value = 'A';
// helper struct that saves us from partially specialized method overloads
template < class RequestedType, class ActualType, class TContentHolder >
struct Getter;
// holds a vector of type TContent, recursively inherits from holders of other types
template < class TContent, class TAddContentHolders >
class ContentHolder : public ContentHolder< typename TAddContentHolders::ContentType, typename TAddContentHolders::AdditionalContentTypes >
{
public:
typedef TContent ContentType;
typedef TAddContentHolders AdditionalContentTypes;
private:
typedef ContentHolder< typename TAddContentHolders::ContentType, typename TAddContentHolders::AdditionalContentTypes > ParentType;
public:
vector< ContentType > mVector;
ContentHolder()
{
for ( int i = 0; i < 5; ++i )
{
mVector.push_back( ContentType(value++) );
}
}
virtual ~ContentHolder() {}
template < class RequestedType >
RequestedType get()
{
return Getter< RequestedType, ContentType, ContentHolder < TContent, TAddContentHolders > >::get(this);
}
};
// specialization for ending the recursion
template < class TContent >
class ContentHolder< TContent, bool >
{
public:
typedef TContent ContentType;
typedef bool AdditionalContentTypes;
vector< ContentType > mVector;
ContentHolder()
{
for ( int i = 0; i < 5; ++i )
{
mVector.push_back( ContentType(value++) );
}
}
virtual ~ContentHolder() {}
template < class RequestedType >
RequestedType get()
{
return Getter< RequestedType, ContentType, ContentHolder< ContentType, bool > >::get(this);
}
};
// default getter: forwards call to parent type
template < class RequestedType, class ActualType, class TContentHolder >
struct Getter
{
static RequestedType get(TContentHolder* holder)
{
cout << "getter 1" << endl;
return Getter< RequestedType, typename TContentHolder::ContentType, typename TContentHolder::AdditionalContentTypes >::get(holder);
}
};
// specialized getter for when RequestedType matches ActualType: return value from holder
template < class RequestedType, class TContentHolder >
struct Getter< RequestedType, RequestedType, TContentHolder >
{
static RequestedType get(TContentHolder* holder)
{
cout << "getter 2" << endl;
return holder->mVector[0];
}
};
// specialized getter for end of recursion
template < class RequestedType >
struct Getter< RequestedType, RequestedType, bool >
{
static RequestedType get(ContentHolder< RequestedType, bool >* holder)
{
cout << "getter 3" << endl;
return holder->mVector[0];
}
};
以下是您如何使用它:
// excuse the ugly syntax
class MyHolder : public ContentHolder< int, ContentHolder< bool, ContentHolder< char, bool > > >
{
};
int main() {
MyHolder h;
cout << h.get<int>() << endl; // prints an int
cout << h.get<bool>() << endl; // prints a bool
cout << h.get<char>() << endl; // prints a char
//cout << h.get<float>() << endl; // compiler error
return 0;
}
这一切都很好,花花公子,满足上述所有要求。但是,get<float>()
的编译器错误真的很难看。所以我尝试引入Getter
的另一个专门化,它解释了当我们到达类层次结构时仍然没有找到匹配类型的情况:
// static assert helper
template <bool b>
struct StaticAssert {};
template <>
struct StaticAssert<true>
{
static void test(const string& s) {}
};
template < class RequestedType, class NonMatchingType >
struct Getter< RequestedType, NonMatchingType, bool >
{
static RequestedType get(ContentHolder< NonMatchingType, bool >* holder)
{
cout << "getter 4" << endl;
StaticAssert<false>::test("Type not in list");
return 0;
}
};
但是这样,即使我没有调用get<float>()
,编译也会在静态断言上失败。更奇怪的是,如果我也删除静态断言并简单地返回0,代码编译并运行而不会打印&#34; getter 4&#34;!
问题:是什么给出的?根据我的理解,模板只有在需要时才会被实例化,但Getter 4永远不会被执行。为什么编译器实例化Getter 4?
答案 0 :(得分:1)
编译器可以编译“getter 4”成员函数,因为代码不依赖于模板参数。如果您使代码依赖于模板参数,则在您使用特定类型对其进行实例化之前,编译器无法对其进行编译。实现此目的的一种简单方法是在静态断言中使用类型。
template < class RequestedType, class NonMatchingType >
struct Getter< RequestedType, NonMatchingType, bool >
{
static RequestedType get(ContentHolder< NonMatchingType, bool >* holder)
{
cout << "getter 4" << endl;
StaticAssert<sizeof(NonMatchingType) == 0>::test("Type not in list");
return 0;
}
};