Bla*_*son 3 c++ templates generic-programming
处理某些类型需要使用成员/方法访问的事实的最佳方法是什么.操作员,而其他人使用 - >操作员.
编写代码是最好的.运算符并让调用者包装类型如下面的代码示例所示.
来自C#背景我不习惯这个特殊问题.
#include <iostream>
#include <string>
#include <vector>
#include <memory>
template<class T>
class container{
public:
void add(T element){
elements_.push_back(std::move(element));
}
void process(){
for(auto& a: elements_){
a.print();
}
}
private:
std::vector<T> elements_;
};
class printable{
public:
void print(){
std::cout << "Print\n";
}
};
template<class T>
class printable_forwarder{
public:
printable_forwarder(T element): element_{std::move(element)}{
}
void print(){
element_->print();
}
private:
T element_;
};
int main()
{
container<printable> c1;
c1.add(printable{});
c1.process();
container<printable_forwarder<std::shared_ptr<printable>>> c2;
std::shared_ptr<printable> sp{std::make_shared<printable>()};
c2.add(printable_forwarder<decltype(sp)>{sp});
c2.process();
}
Run Code Online (Sandbox Code Playgroud)
这看起来更好吗?
#include <iostream>
#include <string>
#include <memory>
#include <type_traits>
#include <vector>
template<typename T>
class dereference
{
public:
inline static T& get(T& value){
return value;
}
};
template<typename T>
class dereference<T*>
{
public:
inline static typename std::add_lvalue_reference<typename std::remove_pointer<T>::type>::type get(T* value){
return *value;
}
};
template<typename T>
class dereference<std::shared_ptr<T>>
{
public:
inline static T& get(std::shared_ptr<T> value){
return *value.get();
}
};
template<class T>
class container{
public:
void add(T const& v){
items_.push_back(v);
}
void print_all(){
for(auto& a: items_){
dereference<T>::get(a).print();
}
}
private:
std::vector<T> items_;
};
struct printable{
void print(){
std::cout << "Printing\n";
}
};
int main()
{
container<printable> c1;
c1.add(printable{});
c1.print_all();
container<std::shared_ptr<printable>> c2;
c2.add( std::shared_ptr<printable>(new printable{}));
c2.print_all();
}
Run Code Online (Sandbox Code Playgroud)
Bar*_*rry 12
处理某些类型需要使用成员/方法访问的事实的最佳方法是什么.操作员,而其他人使用 - >操作员.
只是不要.
你的工作就是写作template<class T> class container.那个容器装有Ts.如果您的用户想要对其执行某些操作,则T应该展示执行某些操作的能力 - 但是他们有责任正确执行该操作.否则,你只是增加了大量的代码膨胀.太棒了,你给了我一个打印所有元素的方法,但如果我知道要调用foo()它们,或者找到第一个bar()返回大于42的元素的元素怎么办?很显然,你不会写for_each_foo()和find_if_bar_is_42().
这就是标准库将容器与算法分开的原因.让你的容器,可用作可能的方式是把它公开两个iterator通过S begin()和end(),然后我可以做任何我需要做的用户:
container<T> values;
values.add(...);
// I know to use '.'
for (T& t : values) {
t.print();
}
container<T*> pointers;
pointers.add(...);
// I know to use '->'
for (T* t : pointers) {
t->print();
}
auto iter = std::find_if(pointers.begin(), pointers.end(), [](T* t){
return t->bar() == 42;
});
Run Code Online (Sandbox Code Playgroud)
除此之外,您可以添加一些自己使用callables的成员函数,因此您将工作传递给用户:
template <class F>
void for_each(F&& f) {
for (auto& elem : elements_) {
f(elem); // option a
std::invoke(f, elem); // option b, as of C++17
}
}
Run Code Online (Sandbox Code Playgroud)
所以上面的例子是:
values.for_each([](T& t){ t.print(); });
pointers.for_each([](T* t){ t->print(); });
values.for_each(std::mem_fn(&T::print));
pointers.for_each(std::mem_fn(&T::print));
Run Code Online (Sandbox Code Playgroud)
请注意,始终由用户知道该怎么做.另外,如果你std::invoke()在执行中使用for_each,那么你可以写:
pointers.for_each(&T::print);
values.for_each(&T::print);
Run Code Online (Sandbox Code Playgroud)
并且,就此而言:
container<std::unique_ptr<T>> unique_ptrs;
unique_ptrs.for_each(&T::print);
Run Code Online (Sandbox Code Playgroud)