<table border="1" cellspacing="0" cellpadding="8">
<tr>
<th>Issue</th>
<td>
<a href=https://github.com/llvm/llvm-project/issues/128364>128364</a>
</td>
</tr>
<tr>
<th>Summary</th>
<td>
[Clang++] What type alias should be selected when used together with "deducing this"?
</td>
</tr>
<tr>
<th>Labels</th>
<td>
clang
</td>
</tr>
<tr>
<th>Assignees</th>
<td>
</td>
</tr>
<tr>
<th>Reporter</th>
<td>
BlankSpruce
</td>
</tr>
</table>
<pre>
I have an inheritance chain where derived class does something extra before delegating to base class implementation.
<details>
<summary>Here's an example implementing this kind of behaviour with virtual functions</summary>
```c++
#include <print>
struct Solver
{
int state = 0;
int step()
{
if (state++ == 2)
{
return state;
}
return solve();
}
virtual int solve()
{
return step();
}
};
struct VerboseSolver : public Solver
{
using Base = Solver;
int solve() override
{
std::println("Current state: {}", state);
return Base::solve();
}
};
struct ExtraVerboseSolver : public VerboseSolver
{
using Base = VerboseSolver;
int solve() override
{
std::println("Remaining iterations (prediction): {}", 3 - state);
return Base::solve();
}
};
template <typename SolverT>
void example()
{
SolverT solver{};
auto result = solver.solve();
std::println("Result: {}", result);
std::println("");
}
int main()
{
std::println("Example: Solver");
example<Solver>();
std::println("Example: VerboseSolver");
example<VerboseSolver>();
std::println("Example: ExtraVerboseSolver");
example<ExtraVerboseSolver>();
}
```
</details>
<details>
<summary>Expected outcome:</summary>
```
Example: Solver
Result: 3
Example: VerboseSolver
Current state: 0
Current state: 1
Current state: 2
Result: 3
Example: ExtraVerboseSolver
Remaining iterations (prediction): 3
Current state: 0
Remaining iterations (prediction): 2
Current state: 1
Remaining iterations (prediction): 1
Current state: 2
Result: 3
```
</details>
[Example on Godbolt.](https://godbolt.org/z/nsh9d6dT9) All three major compilers agree on the visible behaviour.
I've tried expressing this behaviour with "deducing this" feature to avoid virtual functions and maintain cooperative nature of all these classes.
<details>
<summary>Code:</summary>
```c++
#include <print>
struct Solver
{
int state = 0;
template <typename Self>
int step(this Self&& self)
{
if (self.state++ == 2)
{
return self.state;
}
return self.solve();
}
template <typename Self>
int solve(this Self&& self)
{
return self.step();
}
};
struct VerboseSolver : public Solver
{
using Base = Solver;
template <typename Self>
int solve(this Self&& self)
{
std::println("Current state: {}", self.state);
return self.Base::solve();
}
};
struct ExtraVerboseSolver : public VerboseSolver
{
using Base = VerboseSolver;
template <typename Self>
int solve(this Self&& self)
{
std::println("Remaining iterations (prediction): {}", 3 - self.state);
return self.Base::solve();
}
};
template <typename SolverT>
void example()
{
SolverT solver{};
auto result = solver.solve();
std::println("Result: {}", result);
std::println("");
}
int main()
{
std::println("Example: Solver");
example<Solver>();
std::println("Example: VerboseSolver");
example<VerboseSolver>();
std::println("Example: ExtraVerboseSolver");
example<ExtraVerboseSolver>();
}
```
</details>
The issue arises when I want to access base class function by referring through type alias for that base class (`self.Base::solve()`). In `ExtraVerboseSolver` example it seems that `Base` type alias visible in `VerboseSolver::solve` is one defined in `ExtraVerboseSolver` which leads to infinite recursion `VerboseSolver::solve -> VerboseSolver::solve`. As far as I can guess it looks like that `Base` alias in `VerboseSolver` is shadowed by `Base` alias in `ExtraVerboseSolver` as if "deducing this" contributed to type alias resolution as well. It can be mitigated by using base class name instead of a type alias. However GCC doesn't require that mitigation and behaviour follows my virtual functions example. Example on Godbolt for all three major compilers with and without type alias: https://godbolt.org/z/4fYK8s344
Unfortunately I don't know what's standard compliant behaviour hence the question in the title. Is GCC right in this case?
</pre>
<img width="1" height="1" alt="" src="http://email.email.llvm.org/o/eJzsWEuT6rgV_jVic-pSbpnnggUNzQyVXeYmqSyFdYw1LUuMHnA7vz4lyWA3mG5uTe5kFlPlqm7s8_o-nSN9NrNW7BXigoyfyXg9YN5V2iyeJVOvvxyML3Cw0_xtsYWKHRGYAqEqNMIxVSAUFRMKThUaBI5GHJFDIZm1wDVasLpGVwm1B_zmDIMdljpaStwzF-47DTtmsXES9UFijcoxJ7QaAsmW4cpXHB0T0pL8Jf22vq6ZeSP5y89okNCpDZXhNxYCtGFihkpYeBWKgy5hhxU7Cu0NnISr4CiM80xC6VURMlqSrwjdtNGbAiZZugpCn8OVLQnNhSqk5wgkXx2MUO5ibp3xhYNftDyiCbemwQMAQCgH1jEXnNaQkfw5ebTP8EDojNB5c7N1jSYlEDqLAVIhIUyIRFuPjpdB541KCVOq1mDd-XW2C_U22S_WyTL8OHMV6-yY9hV6yXyBcx1wur6Ab-j6J5qdtphYA5Iv4eB3UhR9PHobVvY5NE6A31jcsNlWCfqIxgiOveVax0m-JPkyrqNU0YeuvDF4XrBQT3CargmlhK6auxdkDeJQUgr1EZu34F_CeNxl4N2Dj4h4b_g_5uPvWDOhQj7h0MQJtaEfDwa5iOMTsV7xlMOXa67eN8l3U-awPsg0Qyv3dkDFamxa4GuawaMW_LwZXLq0hdjYJj5MU22XLOadBoPWSxdpTYbD3vrucRWcb8hIMVv_fud4NSaX-QsLGPjvwdMf5aXBny_P89EJG9zOBOWrc7-8dME9Gvx9z93NcdWaN6k-zXM7Iu-StZl6DK_SJU7Pm3o6UQjdvD9kPjl3Xr4dsHDIQXtX6Dq18IeHB8mWt2uSLdtWyZPDXW6z5c2WlPXdfOq7ST9J1cNacHhw5PN7xT0cgd5D8nCER2F_vu7j54YY0Ap-0nynpRuS8ZrQWeXcwYa1phtCN_vmmTZ7Qjf_IXSjbDXnE_51HjbZpZTgKoMINftVGyh0fRASjQW2D3e1AlchHIUVO4mtOBmmOraETo8IzggM29nBoLUXRXOlZAilHLkvzs8JpVAic95g0Fgsbok3cgeY4nFXcUHGFVofIsNHBJVcdQksgsCzRkP7kCxbaf7ASPxIPdV_TKAsU9wryRU5jU_phNAJ2PjvhzIMZTn8bi3WOj0gyKLxzaHTSrLvQNlEeQjm-1r_bxLuR0D7PYKvs979SiZa_GkV4B9O5-_Qiz-I6r-U41_K8Q9Rjl8rBGGtR2BGWLRwqlDBFk5MuXgcFwVa2_3ycT6SYfcGBsvwchZPcqP9voLQrMCkYBZKbcBVzHWdQ4mT7IOZmGSEzoewVUAmWQ_KSdZ-O3FgEWubkpBJFiNOsm4NZ8EiYrwrwtrckwyEBa0QOJZCIW8c-gs4VaKoQCLjNlAkVCmUcAgGC29soOaDXPCF5C_Xm1-3kiEsLZTMALOwhYIp2PuwBMKB1PrVghSveIM5we2DmbDZinF9Qh5W7Y5bP9jwuOwVbYVWzoidD68WTndZN2i19LFJmIUTSjmErYtYdgi1cGLPXKolHQqdDok7nVDWIYvfwVgn8BB-1icMB85Pq1X8bqcInTow-JsXpiGlCR-TK95Rn6WWUp8s1G898rJpqiHc6unYyOyuQI6iNmQK_2jvOvWGkf5Mho_Kf_9tZvPRKM3jP1SpjfOKOZRvsAWuE8RXpU9wqpiLXxCtY4ozw2MZUoRZbXFWqAqMcv03jzYSIZJ8d8IFiFsb-TNiX7n0SFgo4jhuSLYc8EXO5_mcDXDxNB1ldDSaZ7NBtZiV2ZSPR-MdL-azyWQ6YpzNR3TEMR_jeFoOxIJmdJxRSp-m9GmUD2f5ZDQaT8pZieMxzhgZZeGolUMpj3UgYRD3nsUTDZYDyXYobfy-S2khmdqH7W-8HphFcPiy83tLRpkU1tk2REQVnFbJI-r08Rr-Fbqh05W20l6Ghghncnojjpudt7GB9-gqvP-OQvLNwBu5uFpP4Sq_Gxa6JnQTKmr-fDkY_SsWjtBNRGgJ3TQgjwv63wAAAP__bBb3rg">