托管的泛型在dot Net framework中属于基础设施,被每个托管语言所支持,当然也被IL语言支持,但只有C++/CLI支持托管模板。
托管模板比泛型要方便得多,主要得益于编译期类型检查比运行期的检查更加方便。
也只有C++/CLI可以将托管模板翻译成托管泛型,就可以供其它托管语言(比如C#和VB)。但是,因为要进行类型实例化,所以不能避免代码膨胀的问题。
例子:
- 制造接口
namespace test
{
generic<typename T>
public interface class IStack
{
void push(T);
T pop();
void print(); //打印栈内容,不是必选项
};
}
- 制作从接口继承的模板
模版对接口进行了实现,用泛型返回特定的类型实现。
namespace test
{
template<typename T>
public ref class stack : IStack<T>
{
ref struct Node
{
T obj;
Node^ next = nullptr;
Node(T obj, Node^ top) : obj(obj), next(top) {}
};
Node^ Top = nullptr;
public:
virtual void push(T obj)
{
Top = gcnew Node(obj,Top);
}
virtual T pop()
{
if (Top)
{
auto obj = Top->obj;
Top = Top->next;
return obj;
}
return T();
}
virtual void print()
{
auto t = Top;
while (t)
{
outputVal(t->obj);
t = t->next;
}
}
};
}
还可以为托管模板添加特化版本,dot Net泛型是不支持特化的。但不影响导出的时候进行识别。
下面是对System::String^的特化。
template<>
public ref class stack<String^> : IStack<String^>
{
cliext::vector<String^> data;
public:
virtual void push(String^ str)
{
data.push_back(str);
}
virtual String^ pop()
{
if (!data.empty())
{
auto bk = data.back();
data.pop_back();
return bk;
}
return nullptr;
}
virtual void print()
{
for(auto cur = data.rbegin();cur != data.rend();++cur)
Console::WriteLine(*cur);
}
};
- 制作泛型工厂类
namespace test
{
public ref class stackMaker
{
public:
generic<typename T>
static IStack<T>^ CreateStack()
{
if (T::typeid == int::typeid)
{
return safe_cast<IStack<T>^>(gcnew stack<int>);
}
else if (T::typeid == String::typeid)
{
return safe_cast<IStack<T>^>(gcnew stack<String^>);
}
else if (T::typeid == double::typeid)
{
return safe_cast<IStack<T>^>(gcnew stack<double>);
}
else if (T::typeid == long::typeid)
{
return safe_cast<IStack<T>^>(gcnew stack<long>);
}
else if (T::typeid == char::typeid)
{
return safe_cast<IStack<T>^>(gcnew stack<char>);
}
else if (T::typeid == short::typeid)
{
return safe_cast<IStack<T>^>(gcnew stack<short>);
}
throw gcnew System::TypeAccessException("invalid type");
}
};
}
反编译后的IL如下:
cppcli-genericAndTemplate.png总结:泛型仅仅是模板的包装,不是在运行阶段实例化,而是返回了编译阶段模板的实例化。不能避免代码的膨胀问题。通过利用托管泛型将模板导出为程序集接口,可以供其它托管语言使用,大大提高了代码复用。
网友评论