bob*_*obo 5 c++ templates members
说你写的是一个非常糟糕的课程
template <typename T>
class IntFoo
{
T container ;
public:
void add( int val )
{
// made an assumption that
// T will have a method ".push_front".
container.push_front( val ) ;
}
} ;
Run Code Online (Sandbox Code Playgroud)
忽略一个事实,即类假定容器将是something<int>,而是注意这个事实
IntFoo< list<int> > listfoo ;
listfoo.add( 500 ) ; // works
IntFoo< vector<int> > intfoo;
//intfoo.add( 500 ) ; // breaks, _but only if this method is called_..
Run Code Online (Sandbox Code Playgroud)
一般来说,可以像这样调用参数化类型的成员函数吗?这是不好的设计吗?这个(反)模式有名字吗?
Xeo*_*Xeo 12
这是非常好的,称为编译时鸭子类型,并在标准库本身的各种地方使用.严肃地说,如果不假设模板参数支持某些功能,你会如何对模板做任何有用的事情?
我们来看看stdlib 中的任何算法,例如std::copy:
template<class InIt, class OutIt>
OutIt copy(InIt first, Init last, OutIt out){
for(; first != last; ++first)
*out++ = *first;
return out;
}
Run Code Online (Sandbox Code Playgroud)
这里,InIt假定类型的对象支持operator*()(用于间接)和operator++()用于推进迭代器.对于类型的对象OutIt,它被假定为支持operator*(),和operator++(int).一般的假设是,*out++从任何*first产量返回的任何东西都是可分配的(也就是可转换的).另一种假设是,这两个InIt和OutIt的拷贝构造.
另一个使用的地方是任何标准容器.在C++ 11中,当您使用时std::vector<T>,当且仅当您使用需要副本的任何成员函数时,才T需要可复制构造.
所有这一切使得用户定义的类型可以被视为与内置类型相同,即,他们是该语言的拳头级公民.让我们再看一些算法,即采用要在范围上应用的回调的算法:
template<class InIt, class UnaryFunction>
InIt for_each(InIt first, InIt last, UnaryFunction f){
for(; first != last; ++first)
f(*first);
return first;
}
Run Code Online (Sandbox Code Playgroud)
InIt假设再次支持与上例中相同的操作copy.但是,现在我们也有了UnaryFunction.假设这种类型的对象支持post-fix函数调用表示法,特别是一个参数(一元).进一步假设这个函数调用的参数可以从任何*first产量转换.
使用此算法的典型示例是使用普通函数:
void print(int i){ std::cout << i << " "; }
int main(){
std::vector<int> v(5); // 5 ints
for(unsigned i=0; i < v.size(); ++i)
v[i] = i;
std::for_each(v.begin(), v.end(), print); // prints '0 1 2 3 4 '
}
Run Code Online (Sandbox Code Playgroud)
但是,您也可以使用函数对象 - 用户定义的重载类型operator():
template<class T>
struct generate_from{
generate_from(T first) : _acc(first) {}
T _acc;
void operator()(T& val){ val = _acc++; }
};
int main(){
std::vector<int> v(5); // 5 ints
// yes, there is std::iota. shush, you.
std::for_each(v.begin(), v.end(), generate_from<int>(0)); // fills 'v' with [0..4]
std::for_each(v.begin(), v.end(), print); // prints '0 1 2 3 4 '
}
Run Code Online (Sandbox Code Playgroud)
正如您所看到的,我的用户定义类型generate_from可以像函数一样处理,可以将其称为函数.请注意,我作出若干假设T的generate_from,即它需要:
operator())operator())