我正在尝试构建一个命令模式,其中每个命令都可以访问定义的接口。接收者实现一个或多个这些接口,然后可以通过应用于它们的 CommandList 来接收命令。我已包含下面的代码和编译器资源管理器链接。我希望两个模板都能应用,创建一个重载集,然后 std::visit (在 lambda 的帮助下)能够根据参数消除歧义,但这显然不是它的工作原理。有人可以解释为什么这不起作用,以及我必须解决哪些选项吗?谢谢!
<source>: In instantiation of 'void MultiReceiver<Interface, Interfaces>::applyCommandList(CommandList) [with Interface = ICatalogue; Interfaces = {IInventory}; CommandList = std::vector<std::variant<std::shared_ptr<Command<ICatalogue> >, std::shared_ptr<Command<IInventory> > >, std::allocator<std::variant<std::shared_ptr<Command<ICatalogue> >, std::shared_ptr<Command<IInventory> > > > >]':
<source>:110:26: required from here
<source>:41:53: error: request for member 'applyCommand' is ambiguous
41 | std::visit([=,this](auto& c){ this->applyCommand(*c); }, command);
| ~~~~~~^~~~~~~~~~~~
<source>:30:14: note: candidates are: 'void Receiver<Interface>::applyCommand(Command<Receiver<Interface> >) [with Interface = IInventory]'
30 | void applyCommand(Command<Receiver> command) {
| ^~~~~~~~~~~~
<source>:30:14: note: 'void Receiver<Interface>::applyCommand(Command<Receiver<Interface> >) [with Interface = ICatalogue]'
Compiler returned: 1
#include <cinttypes>
#include <functional>
#include <memory>
#include <iostream>
#include <vector>
#include <variant>
#include <unordered_map>
template <class Receiver>
class Command {
public:
virtual void execute(Receiver& receiver) = 0;
};
class Product {
public:
Product(std::string name): _name(name) {};
std::string getName() const { return _name; };
bool operator==(const Product&) const = default;
private:
std::string _name;
};
template<class ...Receivers>
using CommandList = std::vector<std::variant<std::shared_ptr<Command<Receivers>>...>>;
template <class Interface>
class Receiver {
public:
void applyCommand(Command<Receiver> command) {
command.execute(*this);
}
};
template <class Interface, class ...Interfaces>
class MultiReceiver: public Receiver<Interface>, public Receiver<Interfaces>... {
public:
using CommandList = ::CommandList<Interface, Interfaces...>;
void applyCommandList(CommandList commands) {
for(const auto& command: commands ) {
std::visit([=,this](auto& c){ this->applyCommand(*c); }, command);
}
};
};
class ICatalogue {
public:
class AddProductCommand;
private:
virtual void addProduct(const Product& product) = 0;
};
class IInventory {
public:
class AddItemsCommand;
private:
virtual void addItems(Product product, uint32_t quantity) = 0;
};
class ICatalogue::AddProductCommand: public Command<ICatalogue> {
public:
AddProductCommand(Product product): _product { product } {};
void execute(ICatalogue& catalogue) {
catalogue.addProduct(_product);
}
private:
Product _product;
};
class IInventory::AddItemsCommand: public Command<IInventory> {
public:
AddItemsCommand(Product product, uint32_t quantity): _product {product}, _quantity{quantity} {};
void execute(IInventory& inventory) {
inventory.addItems(_product, _quantity);
}
private:
Product _product;
uint32_t _quantity;
};
class Catalogue: public ICatalogue {
private:
void addProduct(const Product& product) override {
_product.push_back(product);
}
std::vector<Product> _product {};
};
auto productHash = [](const Product& p){ return std::hash<std::string>{}(p.getName()); };
class Inventory: public IInventory {
private:
void addItems(Product product, uint32_t quantity) override {
_inventory[product] += quantity;
};
std::unordered_map<Product, uint32_t, decltype(productHash)> _inventory {10, productHash};
};
class Shop: public Catalogue, public Inventory, public MultiReceiver<ICatalogue, IInventory> {
};
int main() {
Product banana { "Banana" };
Shop::CommandList commandList {
std::make_shared<ICatalogue::AddProductCommand>(banana),
std::make_shared<IInventory::AddItemsCommand>(banana, 12)
};
Shop shop;
shop.applyCommandList(commandList);
return 0;
}
这与
std::visit
无关,也与重载解析无关。
this->applyCommand
本身的名称查找失败了。您的类有多个基类,这些基类具有不同的 applyCommand
成员函数,因此名称查找不明确。类成员的名称查找要求仅在基类之一中明确找到名称。
如果您的目的是使基类的每个成员都可用于派生类中的重载解析,那么您需要在派生类中使用
using
声明显式地使它们可用:
using Receiver<Interface>::applyCommand;
using Receiver<Interfaces>::applyCommand...;
但是,它会导致重载决策失败,因为没有一个重载是可行的。您尝试将
Command<SomeInterface>
传递给 applyCommand
,但其参数需要 Command<Receiver<SomeInterface>>
。