c ++模板类;函数用任意容器类型,如何定义呢? [英] c++ template class; function with arbitrary container type, how to define it?

查看:172
本文介绍了c ++模板类;函数用任意容器类型,如何定义呢?的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

好的,简单的模板问题。说我定义我的模板类这样:

  template< typename T& 
class foo {
public:
foo(T const& first,T const& second):first(first),second(second){}

template< ;类型名C>
void bar(C& container,T const& baz){
// ...
}
private:
T first;
T second;
}

问题是关于我的吧功能...我需要它使用某种类型的标准容器,这就是为什么我包含了template / typename C部分,以定义该容器类型。但显然这不是正确的方法,因为我的测试类然后抱怨:



错误:'bar'未在此范围内声明



那么我如何去实现我的bar函数正确的方式?也就是说,作为我的模板类的函数,与任意容器类型...我的模板类的其余部分工作正常(有其他函数不会导致错误),它只是一个函数是有问题的。 / p>

编辑:
好​​吧,所以特定的函数(bar)是一个eraseInRange函数,擦除指定范围内的所有元素:

  void eraseInRange(C& container,T const& firstElement,T const& secondElement){...} 

如何使用它的示例如下:

  eraseInRange(v,7,19); 

其中v是这种情况下的向量。



编辑2:
傻的我!我应该声明函数在我的类之外,而不是在它...相当令人沮丧的错误,做。无论如何,感谢大家的帮助,虽然问题有点不同,信息确实帮助我构建函数,因为发现我的原始问题后,我没有得到一些其他愉快的错误。非常感谢!

解决方案




Traits解决方案>

一般化不超过所需数量,而不是更少。



情况下,解决方案可能不够,因为它将匹配任何具有此类签名的模板(例如 shared_ptr ),在这种情况下,您可以使用 type_traits ,非常像鸭式输入(模板一般是鸭式输入) 。

  #include< type_traits> 

//帮助确定是否有T的const_iterator。
template< typename T>
struct has_const_iterator
{
private:
template< typename C> static char test(typename C :: const_iterator *);
template< typename C>静态int测试(...);
public:
enum {value = sizeof(test< T>(0))== sizeof(char)};
};


//对于定义const_iterator的容器定义bar(),将
//定义为value_type。
template< typename Container>
typename std :: enable_if< has_const_iterator< Container> :: value,
void> :: type
bar(const Container& c,typename Container :: value_type const& t)
{
//注意:value_type不需要额外的检查,检查在函数签名中的
// free。
}


template< typename T>
class DoesNotHaveConstIterator {};

#include< vector>
int main(){
std :: vector< float> C;
bar(c,1.2f);

DoesNotHaveConstIterator< float> b;
bar(b,1.2f); //正确无法编译
}

一个好的模板通常不会人为限制他们有效的类型(为什么他们?)。但想象上面的例子你需要访问一个对象 const_iterator ,那么你可以使用SFINAE和type_traits把这些约束放在你的函数上。






或只作为标准库使用



 模板< typename Iter> 
void bar(Iter it,Iter end){
for(; it!= end; ++ it){/*...*/}
}

#include< vector>
int main(){
std :: vector< float> C;
bar(c.begin(),c.end());
}

有关更多此类示例,请查看< algorithm> ;



这种方法的优势在于其简单性,并且基于诸如 ForwardIterator 之类的概念。它甚至可以用于数组。



$ b




< h2> std 具有 std :: vector 签名的容器 h2>

最简单的解决方案是由Kerrek SB近似,虽然它是无效的C ++。修正的变体如下:

  #include< memory> // for std :: allocator 
template< template< typename,typename> class Container,
typename Value,
typename Allocator = std :: allocator< Value> >
void bar(const Container< Value,Allocator&& c,const Value& t)
{
//
}

:这只适用于具有两个模板类型参数的容器,因此对于 std :: map (感谢Luc Danton)。






任何类型的辅助模板参数(不推荐



任何辅助参数计数的修正版本如下: p>

  #include< memory> // for std :: allocator<> 

template< template< typename,typename ...> class Container,
typename Value,
typename ... AddParams>
void bar(const Container< Value,AddParams ...>& c,const Value& t)
{
//
}

template< typename T>
class OneParameterVector {};

#include< vector>
int main(){
OneParameterVector< float> b;
bar(b,1.2f);
std :: vector< float> C;
bar(c,1.2f);
}

模板容器(感谢Luc Danton)。


Okay, simple template question. Say I define my template class something like this:

template<typename T>
class foo {
public:
    foo(T const& first, T const& second) : first(first), second(second) {}

    template<typename C>
    void bar(C& container, T const& baz) {
        //...
    }
private:
    T first;
    T second;
}

The question is about my bar function... I need it to be able to use a standard container of some sort, which is why I included the template/typename C part, to define that container type. But apparently that's not the right way to do it, since my test class then complains that:

error: 'bar' was not declared in this scope

So how would I go about implementing my bar function the proper way? That is, as a function of my template class, with an arbitrary container type... the rest of my template class works fine (has other functions that don't result in an error), it's just that one function that's problematic.

EDIT: Okay, so the specific function (bar) is an eraseInRange function, that erases all elements in a specified range:

void eraseInRange(C& container, T const& firstElement, T const& secondElement) {...}

And an example of how it would be used would be:

eraseInRange(v, 7, 19);

where v is a vector in this case.

EDIT 2: Silly me! I was supposed to declare the function outside of my class, not in it... pretty frustrating mistake to be making. Anyways, thanks everyone for the help, though the problem was a little different, the information did help me construct the function, since after finding my original problem, I did get some other pleasant errors. So thank you!

解决方案


Traits solution.

Generalize not more than needed, and not less.

In some cases that solution might not be enough as it will match any template with such signature (e.g. shared_ptr), in which case you could make use of type_traits, very much like duck-typing (templates are duck typed in general).

#include <type_traits>

// Helper to determine whether there's a const_iterator for T.
template<typename T>
struct has_const_iterator
{
private:
    template<typename C> static char test(typename C::const_iterator*);
    template<typename C> static int  test(...);
public:
    enum { value = sizeof(test<T>(0)) == sizeof(char) };
};


// bar() is defined for Containers that define const_iterator as well
// as value_type.
template <typename Container>
typename std::enable_if<has_const_iterator<Container>::value,
                        void>::type
bar(const Container &c, typename Container::value_type const & t)
{
  // Note: no extra check needed for value_type, the check comes for
  //       free in the function signature already.
}


template <typename T>
class DoesNotHaveConstIterator {};

#include <vector>
int main () {
    std::vector<float> c;
    bar (c, 1.2f);

    DoesNotHaveConstIterator<float> b;
    bar (b, 1.2f); // correctly fails to compile
}

A good template usually does not artificially restrict the kind of types for which they are valid (why should they?). But imagine in the example above you need to have access to an objects const_iterator, then you can use SFINAE and type_traits to put those constraints on your function.


Or just to as the standard library does

Generalize not more than needed, and not less.

template <typename Iter>
void bar (Iter it, Iter end) {
    for (; it!=end; ++it) { /*...*/ }
}

#include <vector>
int main () {
    std::vector<float> c;
    bar (c.begin(), c.end());
}

For more such examples, look into <algorithm>.

This approach's strength is its simplicity and is based on concepts like ForwardIterator. It will even work for arrays. If you want to report errors right in the signature, you can combine it with traits.


std containers with signature like std::vector (not recommended)

The simplest solution is approximated by Kerrek SB already, though it is invalid C++. The corrected variant goes like so:

#include <memory> // for std::allocator
template <template <typename, typename> class Container, 
          typename Value,
          typename Allocator=std::allocator<Value> >
void bar(const Container<Value, Allocator> & c, const Value & t)
{
  //
}

However: this will only work for containers that have exactly two template type arguments, so will fail miserably for std::map (thanks Luc Danton).


Any kind of secondary template arguments (not recommended)

The corrected version for any secondary parameter count is as follows:

#include <memory> // for std::allocator<>

template <template <typename, typename...> class Container, 
          typename Value,
          typename... AddParams >
void bar(const Container<Value, AddParams...> & c, const Value & t)
{
  //
}

template <typename T>
class OneParameterVector {};

#include <vector>
int main () {
    OneParameterVector<float> b;
    bar (b, 1.2f);
    std::vector<float> c;
    bar (c, 1.2f);
}

However: this will still fail for non-template containers (thanks Luc Danton).

这篇关于c ++模板类;函数用任意容器类型,如何定义呢?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆