###### 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`.