4

我需要一个这样的模板,它工作得很好

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% 的代码对于向量和双端队列等都是相同的。

4

6 回答 6

7

专攻:

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
}

专门针对双端队列:

template<typename C> void mySuperTempalte (std::deque<C> myCont)
{
    //check type of container
    //do something here
}
于 2009-01-02T14:36:13.497 回答
7

您是否尝试过模板类型名参数?语法有点奇怪,因为它模拟了用于声明此类容器的语法。有一篇很好的InformIT 文章更详细地解释了这一点。

template <template <typename> class Container>
void mySuperTemplate(Container<std::string> const& cont) {
}

请注意,您还应该将参数声明为引用!

顺便说一句:这条评论

//check type of container

是一个死的赠品,你做错了什么。您不想检查容器的类型。而是用户更复杂的重载,如 sep 的答案所示。

于 2009-01-02T14:36:13.590 回答
5

如果我正确理解您的问题,那么您有一个适用于 STL 容器向量、双端队列等的算法,但正在尝试为字符串编写模板特化。如果是这种情况,那么您可以编写您在问题中定义的通用模板化方法:-

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 容器执行此操作,则将模板参数作为该容器中类型的参数,而不是像 Sep 建议的容器本身。

template<typename C> void mySuperTempalte( const std::vector<C> &myCont)
{
    // check type of container
    // do something here
}

值得尝试通过使您的第一个实现与所有 STL 容器一起工作以使您的生活更轻松来避免这种情况,然后您只需要对字符串类进行专门化。甚至考虑将您的字符串转换为向量以避免一起专门化。

附带说明一下,我已将容器参数更改为 const 引用,我假设这就是您想要的,因为您无论如何都声明了对象 const,这样您就可以避免复制。

于 2009-01-02T20:17:38.317 回答
4

到目前为止的答案似乎很有帮助,但我想我会使用不同的结构。我希望所有容器都定义 value_type,就像 STL 容器一样。因此,我可以写

inline template <typename C> void mySuperTemplate (C const& myCont)
{
    mySuperTemplateImpl<C, typename C::value_type>(myCont);
}

通常,对明确提取的参数进行操作会更容易。

于 2009-01-02T15:30:00.563 回答
3

@九月

“简单”的解决方案

'sep' 发布的答案非常好,对于 99% 的应用程序开发人员来说可能已经足够好了,但如果它是库界面的一部分,可以使用一些改进,重复一遍:

专门用于矢量:

template<typename C> void mySuperTempalte (std::vector<C> myCont)
{
    //check type of container
    //do something here
}

如果调用者不使用 std::vector,这将起作用。如果这对你来说足够好,专门用于向量、列表等,那么就在这里停下来使用它。

更完整的解决方案

首先,请注意您不能部分特化函数模板——您可以创建重载。如果它们中的两个或多个匹配程度相同,您将得到“模棱两可的过载”错误。因此,我们需要在您想要支持的每种情况下准确匹配。

这样做的一种技术是使用 enable_if 技术—— enable_if 允许您使用晦涩的语言规则有选择地从可能的匹配列表中取出函数模板重载......基本上,如果某个布尔表达式为假,则重载变为“不可见” . 如果您好奇,请查阅 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>
于 2009-01-02T20:10:06.380 回答
1

这是否是一个好的设计还有待进一步讨论。无论如何,您可以使用部分模板特化来检测容器的类型。尤其:

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 );
}
于 2009-01-02T15:34:13.987 回答