适用于STL容器的简单C ++模板
-
03-07-2019 - |
题
我需要一个这样的模板,它完美地运作
template <typename container> void mySuperTempalte (const container myCont)
{
//do something here
}
然后我想专门针对std :: string的上述模板,所以我想出了
template <typename container> void mySuperTempalte (const container<std::string> myCont)
{
//check type of container
//do something here
}
哪个不起作用,并抛出错误。我想让第二个例子起作用然后如果可能我想在模板中添加一些代码以检查是否使用了std :: vector / std :: deque / std :: list,在每个中执行不同的操作案件。 所以我使用模板,因为99%的代码对于矢量和deques等都是相同的。
解决方案
如果我正确理解你的问题你有一个算法可以用于STL容器vector,deque等,但是正在尝试为字符串编写模板特化。如果是这种情况,那么您可以编写在问题中定义的通用模板化方法: -
template<typename container> void mySuperTempalte( const container &myCont )
{
// Implement STL container code
}
然后,对于你的字符串专业化,你声明: -
template<> void mySuperTempalte( const container<std::string> &myCont )
{
// Implement the string code
}
对于任何其他专业化,只需更改myCont的类型声明即可。如果你真的需要为vector和deque容器执行此操作,那么将template参数作为该容器中类型的参数,而不是Sep建议的容器本身。
template<typename C> void mySuperTempalte( const std::vector<C> &myCont)
{
// check type of container
// do something here
}
值得尝试通过使您的第一个实现与所有STL容器一起使用来使您的生活更轻松来避免这种情况,然后您只需要字符串类的特化。甚至考虑将你的字符串转换为向量以避免专业化。
在旁注中,我已经将容器参数更改为const引用,我假设这是您想要的,因为您无论如何都要声明对象const,这样就可以避免复制。
其他提示
专业化:
template<> void mySuperTempalte<std:string>(const std::string myCont)
{
//check type of container
//do something here
}
专注于矢量:
template<typename C> void mySuperTempalte (std::vector<C> myCont)
{
//check type of container
//do something here
}
专门为deque:
template<typename C> void mySuperTempalte (std::deque<C> myCont)
{
//check type of container
//do something here
}
您是否尝试过模板typename参数?语法有点奇怪,因为它模拟用于声明这样一个容器的语法。有一个很好的 InformIT文章,可以更详细地解释这一点。
template <template <typename> class Container>
void mySuperTemplate(Container<std::string> const& cont) {
}
请注意,您还应该将参数声明为参考!
顺便说一下:这个评论
//check type of container
是一个死的赠品,你做错了。您不想要检查容器的类型。用户更复杂的重载,如sep的回答所示。
到目前为止,答案看起来很有帮助,但我想我会使用不同的结构。我希望所有容器都定义value_type,就像STL容器一样。因此,我可以写
inline template <typename C> void mySuperTemplate (C const& myCont)
{
mySuperTemplateImpl<C, typename C::value_type>(myCont);
}
通常,对您明确提取的参数进行操作会更容易。
@sep
'简单'解决方案
'sep'发布的答案非常好,对于99%的应用程序开发人员来说可能已经足够好了,但是如果它是库接口的一部分可以使用一些改进,重复:
专注于矢量:
template<typename C> void mySuperTempalte (std::vector<C> myCont) { //check type of container //do something here }
如果调用者没有使用std :: vector,这将有效。如果这对你来说效果很好,专门用于矢量,列表等,那么就停在这里,然后使用它。
更完整的解决方案
首先,请注意您不能部分专门化功能模板 - 您可以创建重载。如果它们中的两个或多个匹配程度相同,您将得到“模糊过载”。错误。因此,我们需要在您希望支持的每种情况下进行一次匹配。
执行此操作的一种方法是使用enable_if技术--enable_if允许您使用晦涩的语言规则选择性地从可能的匹配列表中取出函数模板重载...基本上,如果某个布尔表达式为false,则重载变为'无形'。如果您感到好奇,可以查询SFINAE获取更多信息。
实施例。可以使用MinGW(g ++ parameterize.cpp)或VC9(cl / EHsc parameterize.cpp)从命令行编译此代码,而不会出现错误:
#include <iostream>
#include <vector>
#include <string>
using namespace std;
template <bool B, class T> struct enable_if {};
template <class T> struct enable_if<true, T> { typedef T type; };
template <class T, class U> struct is_same { enum { value = false }; };
template <class T> struct is_same<T,T> { enum { value = true }; };
namespace detail{
// our special function, not for strings
// use ... to make it the least-prefered overload
template <class Container>
void SpecialFunction_(const Container& c, ...){
cout << "invoked SpecialFunction() default\n";
}
// our special function, first overload:
template <class Container>
// enable only if it is a container of mutable strings
typename enable_if<
is_same<typename Container::value_type, string>::value,
void
>::type
SpecialFunction_(const Container& c, void*){
cout << "invoked SpecialFunction() for strings\n";
}
}
// wrapper function
template <class Container>
void SpecialFunction(const Container& c){
detail::SpecialFunction_(c, 0);
}
int main(){
vector<int> vi;
cout << "calling with vector<int>\n";
SpecialFunction(vi);
vector<string> vs;
cout << "\ncalling with vector<string>\n";
SpecialFunction(vs);
}
输出:
d:\scratch>parameterize.exe calling
with vector<int> invoked
SpecialFunction() default
calling with vector<string> invoked
SpecialFunction() for strings
d:\scratch>
是否是一个好的设计还有待进一步讨论。无论如何,您可以使用部分模板特化来检测容器的类型。特别是:
enum container_types
{
unknown,
list_container,
vector_container
};
template <typename T>
struct detect_container_
{
enum { type = unknown };
};
template <typename V>
struct detect_container_< std::vector<V> > // specialization
{
enum { type = vector_container };
};
template <typename V>
struct detect_container_< std::list<V> >
{
enum { type = list_container };
};
// Helper function to ease usage
template <typename T>
container_types detect_container( T const & )
{
return static_cast<container_types>( detect_container_<T>::type );
}
int main()
{
std::vector<int> v;
assert( detect_container( v ) == vector_container );
}