sus*_*att 5 c++ templates template-specialization template-meta-programming
注意:我知道我在这里做的很多事情在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];
}
};
Run Code Online (Sandbox Code Playgroud)
以下是您使用它的方式:
// 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;
}
Run Code Online (Sandbox Code Playgroud)
这一切都很好,花花公子,满足上述所有要求.但是,编译器错误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;
}
};
Run Code Online (Sandbox Code Playgroud)
但是这样,即使我不调用,编译也会在静态断言上失败get<float>().更奇怪的是,如果我也删除静态断言并简单地返回0,代码编译并运行而不打印"getter 4"!
问题:什么给出了什么?根据我的理解,模板只有在需要时才会被实例化,但Getter 4永远不会被执行.为什么编译器实例化Getter 4?
实例: http ://ideone.com/TCSi6G
编译器可以编译您的“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;
}
};
Run Code Online (Sandbox Code Playgroud)