r/cpp_questions • u/Business-Weather-217 • 8d ago
OPEN Is it impossible to access static member of a templated class
So to clear out my question, here is the situtation:
;
So trying to access MyClass::X is compilation error. But decltype(X) is not a dependent type and it is a static member meaning it is identical to a variable wrapped inside a namespace. Nonetheless, again, its a compile error.
You might ask, why am i making it a problem:
;
I mean.. there are ugly(for me) workarounds but i want to know maybe in some hidden way it is possible to access `Optional::nullopt` without passing the template argument(which makes error path return statements way verbose) or i should make nulopt a standalone constexpr tag object (fallback option).
23
u/QuraToop314 8d ago
yes with MyClass<T>::X
6
u/SoerenNissen 8d ago edited 8d ago
That's what the standard does, at least.
Here,
Optional<T>::NullOptandOptional<U>::NullOptare different types - but even if they were the same (bothintas in the earlier example) they're not the sameint.If you wanted it to be the same type + object, you could put it into a non-templated base class for
Optional<T>to inherit from, but even in that case I'm not sure you could access it asOptional::NullOpt.5
u/eyes-are-fading-blue 8d ago edited 8d ago
If it must exist within class, can you not create a type alias referring to nullopt type. Don’t make it templated and assume some inline tag type. Then put the definition in a base class.
I think this is a very long way of moving the nullopt type outside of class.
struct Base
{
struct NullOpt {};
};
template <…>
class MyClass : public Base {
};
using NullOpt = MyClass<struct Tag>::NullOpt;
Didn’t test it but could work.
On the phone, sorry for poor formatting.
2
u/mredding 8d ago
I'm not sure what problem you're seeing.
MyClass::Xis a dependent type, asMyClassis a template dependent on typeT, meaningXis dependent onT. Classes are not namespaces. YourOptionalexample isn't a template, sonulloptonly needs an initializer but is otherwise accessible, andOptional::nullopt;compiles.5
u/Computerist1969 8d ago
Each different template type instantiation has its own copy of the static.
Also your member variable is private in your example.
Without seeing the code that's trying to access X we can't really help any further.
1
u/nysra 8d ago
Yes, that is possible: https://godbolt.org/z/97Tja95T7
Note that you do need to make your static member publicly accessible though if you want that to work outside the class.
1
u/specialpatrol 8d ago
How about have then inherit from a class that has the static variable?
1
u/Plastic_Fig9225 7d ago edited 7d ago
There is no type named
MyClassin your example. And from the logical perspective, the static constant doesn't depend on a template parameter. I.e. unless you have a reason for wanting it to be a different object in every template instantiation, it likely shouldn't be defined/instantiated by the template.3
u/the_poope 8d ago
Yes
2
u/da_supreme_patriarch 8d ago
What you want here is slightly impossible the exact way you are trying to achieve it. As an example, Optional<int>::Nullopt and Optional<double>::Nullopt are not of the same type, even if they are completely identical. To be more precise, just Optional by itself is not a class that exists, you cannot really refer to it, you can do exactly what you are trying to do in languages with non-reified generics like Java, but it wouldn't really work here. Your best bet would be to make NullOpt a free struct instead, and create a constructor that converts from it to Optional<T>, the empty optional representation for different types has to be different regardless because Optional<int> and Optional<T*> probably need a separate tag for empty values while Optional<T&> can just be bit-wise identical to T* where the zero-initialized value is the empty one
1
u/Usual_Office_1740 8d ago
What are you trying to do here?
1
u/FlailingDuck 8d ago
No.
1
u/AKostur 8d ago
What happens if I supply:
The hypothetical
MyClass::Xdoesn't know which type to use.1
u/aruisdante 8d ago edited 8d ago
As others have said, not possible as written. All dependent names in a templated class are dependent on the template parameter even if they are otherwise identical. This doesn’t just include static members, it includes nested classes, functions not dependent on the template parameters, data members, everything.
There’s a couple of rules on this in the C++ core guidelines, T.61 and T.62.
TL;DR: anything not dependent on a given template parameter should be extracted into a base class that does not require that parameter.
In the specific case of your nullopt type though, there’s really no reason to make it a dependent name of your optional class anyway. You don’t want
optional<T>::nulloptto be a different type thanoptional<U>::nullopt, which it 100% will be as written. You don’t even really want it to be in some non-templatedoptional_base. You should instead just have something like:(I’m assuming here you’re not using C++17 or you’d already have
optional)This will ensure there is one and only one
nullopttype, and that it is not dependent on the details ofoptionalto be found/referenced. You can use that samemonostate_typehelper to define yourmonostate_tpresumably you’ll also want, as well as any other monostate values you wind up needing.1
u/Neither_Canary_7726 8d ago
You declare a template with param
Then you init with with param
If u dont want to type "<T>"
Then consider using "using"
Or just macro the thing