右值引用重载 && 运算符
Posted
技术标签:
【中文标题】右值引用重载 && 运算符【英文标题】:Rvalue reference overloading && operator 【发布时间】:2021-04-23 12:51:40 【问题描述】:我一直在尝试 Dmitri Nesteruk 所著的Design Patterns in Modern C++: Reusable Approaches for Object-Oriented Software Design一书中的示例,并一直在尝试从 S.O.L.I.D. 中编译一个示例。设计原则部分。
代码如下:
// This class demonstrates the Open-Closed
// Principle (OCP) in the S.O.L.I.D. Desgin Principle.
// Software entities (classes, modules, functions, etc.)
// should be open for extension, but closed for modification
#include <iostream>
#include <string>
#include <vector>
enum class Color Red, Green, Blue ;
enum class Size Small, Medium, Large ;
struct Product
std::string name;
Color color;
Size size;
explicit Product(std::string name, Color color, Size size) : namename, colorcolor, sizesize
;
// (Single-Responsibility Principle) our filtering process
// into two part.
// 1) A filter (a process that takes all items and only returns some)
// 2) A specification (the definition of a predicate to apply to a data element)
// =============== Templates to allow classes to be extended =============== //
template <typename T> struct Specification
virtual bool is_satisfied(T* item) = 0;
;
template <typename T> struct Filter
virtual std::vector<T*> filter(std::vector<T*>&, Specification<T>& ) = 0;
;
template< typename T > struct Display
virtual void display(const std::vector<T*>&) = 0;
;
// ========== Product Filter ========== //
struct BetterProductFilter : Filter<Product>
std::vector<Product*> filter(std::vector<Product*>& items, Specification<Product>& spec) override
std::vector<Product*> result;
for (auto& p : items)
if (spec.is_satisfied(p))
result.push_back(p);
return result;
;
// ========== Color specification ========== //
struct ColorSpecification : Specification<Product>
Color color;
ColorSpecification(const Color color) : colorcolor
bool is_satisfied(Product* item) override return item->color == color;
;
// ========== Size specification ========== //
struct SizeSpecification : Specification<Product>
Size size;
SizeSpecification(const Size size) : sizesize
bool is_satisfied(Product* item) override return item->size == size;
;
// ========== Product Display ========== ///
struct ProductDisplay : Display<Product>
void display(const std::vector<Product*> &items)
for(auto &item : items)
std::cout << item->name << std::endl;
;
// =============== Allowing Composite Specifications =============== //
template <typename T> struct AndSpecification : Specification<T>
Specification<T> &first;
Specification<T> &second;
AndSpecification(Specification<T> &first, Specification<T> &second)
: first(first), second(second)
bool is_satisfied(T *item) override
return first.is_satisfied(item) && second.is_satisfied(item);
;
// Overloading the && operator for two specifications
template <typename T> AndSpecification<T> operator&&
(Specification<T>& first, Specification<T>& second)
return AndSpecification<T>(first, second);
// ======= Rvalue Reference Doesn't work with our class implementation ====== //
template <typename T> AndSpecification<T> operator&&
(Specification<T>&& first, Specification<T>&& second)
return AndSpecification<T>(first, second);
int main()
// Initialization of Products
Product apple "Apple", Color::Green, Size::Small ;
Product tree "Tree", Color::Green, Size::Large ;
Product house "House", Color::Blue, Size::Large ;
// Place all the products into a vector
std::vector<Product*> all &apple, &tree, &house;
// Filter & Specification Objects
BetterProductFilter filterObj;
// Avoid making extra variables for specifications
//ColorSpecification green(Color::Green);
//SizeSpecification large(Size::Large);
//auto green_and_large = green && large;
auto green_and_large = ColorSpecification(Color::Green) && SizeSpecification(Size::Large);
// Composite Specifications
//AndSpecification<Product> green_and_large large, green ;
// Product Display Object
ProductDisplay disp;
auto filtered_items = filterObj.filter(all, green_and_large);
disp.display(filtered_items);
return 0;
我重载了 && 运算符以接受对现有对象的两个引用,并且在这段代码的 sn-p 中似乎可以正常工作:
// Overloading the && operator for two specifications
template <typename T> AndSpecification<T> operator&&
(Specification<T>& first, Specification<T>& second)
return AndSpecification<T>(first, second);
主要:
ColorSpecification green(Color::Green);
SizeSpecification large(Size::Large);
auto green_and_large = green && large;
但是当我使用右值引用时,我最终会使用以下代码出现分段错误:
// ======= Rvalue Reference Doesn't work with our class implementation ====== //
template <typename T> AndSpecification<T> operator&&
(Specification<T>&& first, Specification<T>&& second)
return AndSpecification<T>(first, second);
主要:
auto green_and_large = ColorSpecification(Color::Green) && SizeSpecification(Size::Large);
我猜这是这个实现调用 AndSpecification(first, second) 的事实,而这个构造函数只处理对现有对象的引用而不是右值引用。如何修改上面的代码以允许 && 运算符使用右值引用?谢谢!!!
【问题讨论】:
由于AndSpecification
存储引用,因此您需要确保它引用的对象的寿命比它长。 (引用成员的使用让我怀疑这本书是否真的好。)
【参考方案1】:
你的结论是正确的。
如果你只是想获得一个程序。
// it is your ColorSpecification class with copy constructor addition
struct ProductColorSpecification final : Specification<Product>
Color color;
ProductColorSpecification(const Color color)
: Specification<Product>()
, colorcolor
ProductColorSpecification(const ProductColorSpecification& o)
: Specification<Product>()
, coloro.color
bool is_satisfied(Product* item) const override return item->color == color;
;
// it is your SizeSpecification class with copy constructor addition
struct ProductSizeSpecification final : Specification<Product>
Size size;
ProductSizeSpecification(const Size size)
: Specification<Product>()
, sizesize
ProductSizeSpecification(const ProductSizeSpecification& o)
: Specification<Product>()
, sizeo.size
bool is_satisfied(Product* item) const override return item->size == size;
;
struct ProductAndSpecification final : Specification<Product>
ProductColorSpecification *color_spec;
ProductSizeSpecification *size_spec ;
ProductAndSpecification(const Specification<Product>& first_spec, const Specification<Product>& second_spec)
: Specification<Product>()
, color_specnullptr
, size_specnullptr
const auto* spec_f_c = dynamic_cast<const ProductColorSpecification*>(&first_spec );
const auto* spec_f_s = dynamic_cast<const ProductSizeSpecification *>(&first_spec );
const auto* spec_s_c = dynamic_cast<const ProductColorSpecification*>(&second_spec);
const auto* spec_s_s = dynamic_cast<const ProductSizeSpecification *>(&second_spec);
if (spec_f_c && spec_s_s)
color_spec = new ProductColorSpecification(*spec_f_c);
size_spec = new ProductSizeSpecification (*spec_s_s);
else if (spec_f_s && spec_s_c)
color_spec = new ProductColorSpecification(*spec_s_c);
size_spec = new ProductSizeSpecification (*spec_f_s);
else
// bad specs
~ProductAndSpecification()
if (color_spec)
delete color_spec;
if (size_spec)
delete size_spec;
friend ProductAndSpecification operator&&(Specification<Product>&& first, Specification<Product>&& second);
bool is_satisfied(Product *item) const override
if (color_spec && size_spec)
return color_spec->is_satisfied(item) && size_spec->is_satisfied(item);
else if (color_spec)
return color_spec->is_satisfied(item);
else if (size_spec)
return size_spec->is_satisfied(item);
else
return false;
;
struct ProductAndSpecification operator&&(Specification<Product>&& first, Specification<Product>&& second)
return ProductAndSpecification(first, second);
但它仍然是糟糕的设计(我想你明白为什么了)。
PS:: 不要忘记在 main 函数中更改规范对象。
【讨论】:
我试过了,但是我的 Specification以上是关于右值引用重载 && 运算符的主要内容,如果未能解决你的问题,请参考以下文章