C++ Logo

std-proposals

Advanced search

Re: Allow use of constants and types from not-instantiation-ed template

From: DBJ <dbj_at_[hidden]>
Date: Wed, 22 Dec 2021 18:15:29 +0100
Ugly hacks are not proactively stopped. There are many
wonderful opportunities in standard C++ to assemble big and shiny foot guns:

std::vector<void ***> * boom_ {} ;

Abover compiles vey nicely. Prevailing WG21 (and implementers)school of
thought is not to be adding more features and mechanisms to already complex
machinery, to preempt that kind of pathology.

I don't know if I am too open or just off the target?

On Wed, 22 Dec 2021 at 02:10, Maciej Polanski via Std-Proposals <
std-proposals_at_[hidden]> wrote:

>
>
> On 20.12.2021 22:44, Brian Bi wrote:
> > On Sun, Dec 19, 2021 at 2:36 PM Maciej Polanski via Std-Proposals <
> > std-proposals_at_[hidden]> wrote:
> >
> >> Hello,
> >>
> >> So, let's just allow use of a types and static constants from
> >> not-instantiation-ed template class (if possible):
> >>
> >> template<typename T>
> >> struct Foo{
> >> constexpr static int bar = 0x01;
> >> };
> >> int i = Foo::bar; // Doesn't compile now, but
> could
> >> int j = Foo<class Nonexisting>::bar; // Ugly hack but works
> >>
> >>
> >> This improvement should make template configuration behave similar to
> >> class usages.
> >> Classes frequently uses internal class constants, e.g.
> >> "std::cout.setf(std::ios::hex, std::ios::basefield)".
> >>
> >> So this change would allow to include constants and types used to
> >> configure template, inside it.
> >> Ideally, those should be visible inside template-initialization-list
> >> without scope operators.
> >>
> >> HelloWorld example:
> >> ---
> >> #include <iostream>
> >>
> >> // T needed for some functionality not listed here
> >> template <typename T, int flags>
> >> struct HelloWorld
> >> {
> >> static constexpr int Hello = 0x1;
> >> static constexpr int World = 0x2;
> >> static constexpr int Exclamation = 0x4;
> >>
> >> void work(){
> >> if (flags & Hello) // <- no code for this line
> >> std::cout << "Hello ";
> >> if (flags & World) // <- no code for this line
> >> std::cout << "World";
> >> if (flags & Exclamation) // <- no code for this line
> >> std::cout << "!\n";
> >> }
> >> };
> >>
> >> int main()
> >> {
> >> HelloWorld<int, Hello | World | Exclamation>{}.work(); // Prints
> >> "Hello World!"
> >> return 0;
> >> }
> >> ---
> >>
> >> Currently types and constants have to be defined before template,
> >> polluting higher scope. Or ugly hack used:
> >>
> >> HelloWorld<int, HelloWorld<void*, 0>::Hello |
> >> HelloWorld<std::iostream, -1>::World | HelloWorld<class Nonexisting,
> >> 3141592>::Exclamation>{}.work();
> >>
> >> You can see this yourself in Compiler Explorer:
> >> https://godbolt.org/z/s6MP7sqz5
> >>
> >>
> >> Regards,
> >> Maciej
> >>
> >>
> >>
> >>
> >> --
> >> Std-Proposals mailing list
> >> Std-Proposals_at_[hidden]
> >> https://lists.isocpp.org/mailman/listinfo.cgi/std-proposals
> >>
> > The standard workaround for the OP's use case is to move the constants
> into
> > a non-template public base class like std::ios_base. Any proposal for a
> new
> > language feature will need to explain why the current workarounds are
> > inadequate (e.g., too much code duplication). I personally can't see much
> > wrong with the status quo.
> >
>
> Yes, using public non template base class seems to be a good solution to
> a problem with partial specialization that may redefine constants.
>
> But, regarding the main objection, lets have:
>
> struct bar {
> constexpr static int flag1 = 0x1;
> };
>
> template <typename T, int flags>
> struct foo : public bar {
> T t;
> void work() {}
> };
>
> So, how can I make a variable from `foo` template?
>
> foo<int, bar::flag1> f1;
> This approach has a major flow: no obvious link between `foo` and `bar`.
> Me and you know the hierarchy. And the example you gave with ios is also
> valid, everybody knows (or should) that hierarchy.
> But in general case, users does not need to know if template has a base
> and what is it.
> And, more importantly, users can mix up base classes names and use the
> wrong one.
>
> foo<int, foo::flag1> f2;
> This is class-like, as when declaring variable of derived class, the
> flags from base are visible through derived class name.
> But it doesn't compile. Even though the value of flag1 is unambiguous,
> foo's template arguments must be provided.
>
> foo<int, foo<int, 3141592>::flag1> f3;
> This works, but 3141592 is plainly stupid and 0 wouldn't be less magic
> either.
> However, attempt to use "flag1", that could make more sense, generates
> recurrence in declaration.
>
> So, I just think that use like `foo<int, foo::flag1> f2` or even better
> `foo<int, flag1> f2` should be possible.
>
> Thanks,
> Maciej
>
> --
> Std-Proposals mailing list
> Std-Proposals_at_[hidden]
> https://lists.isocpp.org/mailman/listinfo.cgi/std-proposals
>

Received on 2021-12-22 11:15:51