I have found a situation where code compiles successfully under C++17, but FAILS under C++20.
This blocks us from upgrading our existing code design to the newer standard.
Why doesn't this compile under C++20? It seems like a weird breach of backwards-compatibility.
The errors occur when I try to grant friendship to a constructor/destructor of a template class specialization.
I am compiling using MSVC with Ninja.
Compiles successfully under C++17.
Under C++20, I receive these errors:
error C2838: '{ctor}': illegal qualified name in member declaration
error C2838: '{dtor}': illegal qualified name in member declaration
Here is a simplified reproduction of the code that causes the errors under C++20, but compiles successfully under C++17:
template<typename T, int V> class B {};
// specialization of class B
template<typename T> class B<T, 0> {
private:
T _t; // private data member
public:
constexpr inline B(T* p, int i) noexcept; // B constructor declaration
virtual inline ~B() noexcept; // B destructor declaration
};
// empty class with only private static data, no methods
class A {
private:
static int x; // private static variable
public:
// ERRORS HERE IN C++20, but compiles successfully in C++17
template<typename T> friend B<T, 0>::B(T*, int) noexcept; // C++20 ERROR
template<typename T> friend B<T, 0>::~B() noexcept; // C++20 ERROR
};
int A::x = 0; // global definition of private static variable
template<typename T> // B constructor definition
constexpr inline B<T, 0>::B(T* p, int i) noexcept : _t(0) { A::x++; }
template<typename T> // B destructor definition
inline B<T, 0>::~B() noexcept { A::x++; }
int main() {
A a;
B<const int, 0> b(0, 0);
}
I know I can workaround this by granting friendship to the entire class template for B
(including ALL specializations), but this is undesirable because we want to limit friendship to the smallest possible restriction.
Only one or two template specializations (out of dozens) actually require this friendship, and we don't want to grant friendship to the other template specializations if it is not necessary.
/std:c++latest
turns/permissive-
on by default. – Elizebethelizondosince c++11
orsince c++17
ect. so it's probably been there since prior toc++11
at least. Chances are that your code was non-conformant even if it did compile before. – Poppaslanguage-lawyer
tag to the question. – Elizebethelizondo