I have a class that inherits from a class template. The moment I change the derived class into a template, the compiler complains that the base class data member is undefined.
Admittedly, I'm abusing references in a way that might not be legal. But I'm doing so in both versions, so I'm left wondering why the compiler catches the problem in one version but not the other. At first I figured it was a compiler bug, but I get the same results using MSVC and Clang.
// DISCLAIMER: ABSURD EXPERIMENTAL CODE
#include <array>
#include <concepts>
#include <utility>
template <std::size_t N, std::floating_point T>
struct QNT {
template <std::convertible_to<T>... Scalar>
QNT(Scalar... values) : m{static_cast<T>(values)...} {
static_assert(sizeof...(values) == N);
}
std::array<T, N> m;
};
#if CORRECT
using T = float;
#else
template <std::floating_point T>
#endif
struct Q2T : public QNT<2, T> {
template <std::convertible_to<T> Tx, std::convertible_to<T> Ty>
Q2T(Tx xx, Ty yy) : QNT<2, T>(xx, yy), x(m[0]), y(m[1]) {}
T &x;
T &y;
};
If you compile with clang -std=c++20 -DCORRECT=1, the code above will compile cleanly. (And it even does what I was hoping it could do!)
If you change CORRECT to 0, then T is changed from a type alias T (using T = float;) to a template parameter in the derived class. In that case, the base class member no longer seems to be accessible from the derived class.
<source>:21:40: error: use of undeclared identifier 'm'<source>:21:49: error: use of undeclared identifier 'm'
The locations refer to the initializers for x and y in the Q2T constructor. Some folks get confused when they cannot access members of derived class from a base class constructor, but this is the opposite situation. The base class member m should be fully initialized at the point the compiler claims it's undeclared.
In the failing case, it makes no difference whether I actually instantiate an object of Q2T.