microsoft / proxy

Proxy: Next Generation Polymorphism in C++
https://wg21.link/p3086
MIT License
2.16k stars 133 forks source link

can add_convention support function overload? #192

Closed Nu11able closed 21 hours ago

Nu11able commented 4 days ago

I am trying to use proxy, suppose we have two different types of keys; I don't know how to make the Dictionary support different key types. Any example would be appreciated(the following code won't compile)

PRO_DEF_MEM_DISPATCH(MemAt, at);
PRO_DEF_MEM_DISPATCH(MemAt2, at);

struct Dictionary : pro::facade_builder
    ::add_convention<MemAt, std::string(int)>
    ::add_convention<MemAt2, std::string(std::string)>
    ::build {};

/* this code not work either
struct Dictionary : pro::facade_builder
    ::add_convention<MemAt, std::string(int)>
    ::add_convention<MemAt, std::string(std::string)>
    ::build {};
*/

// can't compile
template<typename T>
void PrintDictionary(pro::proxy<Dictionary> dictionary, T&& key) {
  std::cout << dictionary->at(key) << "\n";
}

int main() {
  static std::map<int, std::string> container1{{1, "hello"}};
  static std::map<std::string, std::string> container2{{"hello", "world"}};
  PrintDictionary(&container1, 1);
  PrintDictionary(&container2, "hello");

}
mingxwa commented 3 days ago

@Nu11able Before making Dictionary support different key types, you need to choose whether to define Dictionary as

In your example, looks like you are trying to define a facade that supports both int and std::string as the key type (if you choose the former), which means your implementation types that instantiates pro::proxy<Dictionary> is required to support at expressions with both int and std::string as the argument type. However, each of the provided 2 types (std::map<int, std::string> and std::map<std::string, std::string>) only supports one of the required expressions. Therefore, conversion from std::map<...> to pro::proxy<Dictionary> will fail. To make the code compile, you may need to define a fallback operation (e.g., throw an exception) when the given implementation type does not define some required expressions with macro PRO_DEF_WEAK_DISPATCH.

BTW, the definition of Dictionary in your comment is well-formed. There is no need to redefine a MemAt2. Also, it is allowed to merge the two MemAt conventions into a single line, i.e., add_convention<MemAt, std::string(int), std::string(std::string)>. Please refer to the documentation for more details.

On the other hand, if you want to define a template of facade that only supports one specific type, Dictionary should be defined as a template, e.g.:

template <class T>
struct Dictionary : pro::facade_builder
    ::add_convention<MemAt, std::string(const T&) const>
    ::build {};

Please let me know if there is anything missing.

Nu11able commented 3 days ago

Thank you very much for your helpful reply. My issue has been fully resolved

@Nu11able Before making Dictionary support different key types, you need to choose whether to define Dictionary as

  • a facade that supports more than one key types, or
  • a template of facade that only support one key type for each instantiation.

In your example, looks like you are trying to define a facade that supports both int and std::string as the key type (if you choose the former), which means your implementation types that instantiates pro::proxy<Dictionary> is required to support at expressions with both int and std::string as the argument type. However, each of the provided 2 types (std::map<int, std::string> and std::map<std::string, std::string>) only supports one of the required expressions. Therefore, conversion from std::map<...> to pro::proxy<Dictionary> will fail. To make the code compile, you may need to define a fallback operation (e.g., throw an exception) when the given implementation type does not define some required expressions with macro PRO_DEF_WEAK_DISPATCH.

BTW, the definition of Dictionary in your comment is well-formed. There is no need to redefine a MemAt2. Also, it is allowed to merge the two MemAt conventions into a single line, i.e., add_convention<MemAt, std::string(int), std::string(std::string)>. Please refer to the documentation for more details.

On the other hand, if you want to define a template of facade that only supports one specific type, Dictionary should be defined as a template, e.g.:

template struct Dictionary : pro::facade_builder ::add_convention<MemAt, std::string(const T&) const> ::build {}; Please let me know if there is anything missing.