###### tags: `C++` # C++ visitor pattern with Class Template Argument Deduction(CTAD) and Parameter pack ## Introduce One day, when I see the cppcon [How C++23 Changes the Way We Write Code - Timur Doumler - CppCon 2022](https://www.youtube.com/watch?v=eD-ceG-oByA&t=2534s). I am intersted with the visitor pattern with the c++23 `deducing this` feature. ``` cpp #include<variant> #include <iostream> struct Leaf {}; struct Node; using Tree = std::variant<Leaf, Node*>; struct Node { Tree left, right; }; template <typename... Ts> struct overload : Ts... {using Ts::operator()...;}; int countLeaves(const Tree& tree) { return std::visit(overload{ [](const Leaf&) {return 1;}, [](this const auto& self, const Node* node) -> int { return std::visit(self, node->left) + std::visit(self, node->right); } }, tree); } int main() { Node n1{.left=Leaf{}, .right=Leaf{}}; Node n2{.left=Leaf{}, .right=Leaf{}}; Node n3{.left=Leaf{}, .right=Leaf{}}; Node n4{.left=Leaf{}, .right=Leaf{}}; Node n5{.left=&n1, .right=&n2}; Node n6{.left=&n4, .right=&n3}; Node n7{.left=&n5, .right=&n6}; std::cout<<countLeaves(&n7); } ``` [Code](https://godbolt.org/z/zrK3198sq) ## Implement the overload class in gcc9.2 and c++17. * `deducing this` is a c++23 feature, so we need to remove it. * The following code is compiled error because we don't have deducing guide for overload. * However, c++20 compiles success. ``` cpp #include<variant> #include <iostream> template <typename... Ts> struct overload : Ts... {using Ts::operator()...;}; int main() { // !error: cannot deduce template arguments of 'overload<Ts>', as it has no viable deduction guides overload o{ [](int i){std::cout<<"int "<<i<<std::endl;}, [](double d){std::cout<<"double "<<d<<std::endl;}, }; } ``` ## Fix the error with CTAD. * After adding deducing guide for overload, we don't need to care the template argument of the overload. * Declaring the overload `o` in `print` function and using `std::visit` to visit the parameter `v`. ``` cpp #include<variant> #include <iostream> #include <string> template <typename... Ts> struct overload : Ts... {using Ts::operator()...;}; // Adding the deducing guide for overload. template<typename... Ts> overload(Ts...) -> overload<Ts...>; using var=std::variant<int, double, std::string>; void print(const var& v) { overload o{ [](int i){std::cout<<"int "<<i<<std::endl;}, [](double d){std::cout<<"double "<<d<<std::endl;}, [](const std::string& s){std::cout<<"string: "<<s<<std::endl;} }; std::visit(o, v); } int main() { print(1); print(2.2); print("abc"); } Output: int 1 double 2.2 string: abc ``` ## Take Away 1. use `parameter pack` to declare the `overload` and `Using-declarations` to redirect the `operator()`. 2. use `CTAD` to provide the deducing guide for `overload`. 3. declare a function to accept all type of the `std::variant`.