Self‑referencing structures are among the most fundamental yet advanced data‑design patterns in the C++ language. These structures allow internal relationships between members of the same object and are widely used in data structures such as linked lists, trees, graphs, and memory‑management systems.
However, when this pattern is combined with the constexpr feature in C++, compiler behavior can vary significantly—especially between GCC and compilers like Clang and MSVC.
In this article, based on the discussion from StackOverflow, we provide a fully technical analysis of the problem, the root cause of the differences, practical solutions, and real examples. At the end, we also introduce the services offered by Radib, one of the leading technology companies in Iran.
Main Issue Overview
The following code represents a simple C++ class where a pointer is stored to one of its own data members. The main question is: Is this allowed during compile‑time (constexpr) evaluation?
template <class T>
class Foo {
T t;
const T* t_ptr;
public:
constexpr Foo(T t) : t(t), t_ptr(&this->t) {}
constexpr Foo(const Foo& foo) : t(foo.t), t_ptr(&this->t) {}
constexpr T get_t() const {
return *t_ptr;
}
};
constexpr auto f = Foo(1);
static_assert(f.get_t() == 1);
This code compiles successfully on Clang and MSVC, but GCC produces an error.
Is This Code Valid According to the C++ Standard?
Yes. Under C++20 and C++23, this code is completely valid. During a constexpr constructor call, the object is in the process of being constructed, and taking the address of one of its members is allowed. Therefore:
- Clang behaves correctly
- MSVC behaves correctly
- GCC contains a known bug
According to WG21 documentation, taking the address of a member inside a constructor is a permitted constexpr operation.
Why Does GCC Produce an Error?
In some versions, GCC is unable to properly analyze self‑dependencies during constexpr evaluation and mistakenly assumes that the object is being used while still under initialization, although this is incorrect.
Example of GCC Error Output
error: the value of 'f' is not usable in a constant expression
note: 'f' used in its own initializer
This diagnostic is incorrect and has been acknowledged by many C++ developers as a GCC bug.
Best Solutions for Fixing the Issue in GCC
1) Move pointer initialization into a constexpr helper function
template <class T>
constexpr const T* init_ptr(T& t) {
return &t;
}
template <class T>
struct Foo {
T t;
const T* t_ptr;
constexpr Foo(T v) : t(v), t_ptr(init_ptr(t)) {}
};
2) Using consteval
template <class T>
struct Foo {
T t;
const T* ptr;
constexpr Foo(T v) : t(v), ptr(nullptr) {
ptr = &t;
}
};
3) Two‑phase initialization (Initialize then Patch)
template <class T>
struct Foo {
T t;
const T* ptr;
constexpr Foo(T v) : t(v), ptr(nullptr) {
ptr = &t;
}
};
Practical Applications of Self‑Referencing Structures
Self‑referencing structures form the basis of many important data structures, including:
- Linked lists
- Binary trees
- Graphs
- Memory‑management systems
Example: A constexpr Linked List Node
struct Node {
int value;
const Node* next;
constexpr Node(int v, const Node* n = nullptr)
: value(v), next(n) {}
};
constexpr Node c = Node(1, new Node(2));
(Although new has limitations inside constexpr contexts, it is partially allowed up to C++20. For practical applications, static arrays are preferred.)
Introducing Radib Services
Radib is a leading company in software development, website design, e‑commerce platform creation, SEO optimization, custom programming, UI/UX design, hosting, server solutions, and digital marketing. If you have a project in web development, software engineering, cloud services, or automation, Radib—with its expert team and professional support—is one of the best choices.
Website: radib.com
Conclusion
The code discussed is valid, and GCC’s behavior is a bug. Self‑referencing structures in C++ are powerful and widely used, and combining them with constexpr is one of the strongest techniques available. For advanced C++ or software projects, using professional services such as Radib can dramatically improve development speed and overall product quality.


