Yeah, I knew it would be scary, but I braved it anyway because this has been a recurring pain point for me and has often made me reach for less satisfying alternatives or ones with other draw-backs that I'm not willing to incur (macros limit the design/readability in other ways, among other problems).

This is probably my bad, but I should've probably made it clear that the attribute would apply only to the parameter list for the template class/function it was applied to. So "f" in the example you gave would be just fine and isn't affected by the attribute. Only the template parameter list for "ABC::Color" would be affected, or at least that was the intention. And it could be a rule that only the primary template can have this attribute so as to not fall into the trap of having conflicting attributes on different specializations.

I'm not sure what problem your last example is trying to demonstrate though. I'm not sure if there is supposed to be an implied attribute on S? I definitely wouldn't want enumeration values to be automatically deduced without explicit say-so, which is why I proposed the "context" attribute.
Regardless, the point that Peter brought up about ignorable attributes (nice article on that, by the way!) is a good one and alone makes this a less than solid proposal barring some alternative syntax.

Thanks for the input,
Ryan Klaus

On Mon, Nov 28, 2022 at 11:09 AM Arthur O'Dwyer <arthur.j.odwyer@gmail.com> wrote:
On Mon, Nov 28, 2022 at 11:58 AM Ryan Klaus via Std-Proposals <std-proposals@lists.isocpp.org> wrote:

Correct me if I'm wrong, but don't the current disambiguation rules for using statements cover this?
These conflicts could occur with using statements already allowed in the language.
Here's an example:

enum class ColorComponents {
    RGBA = 7
};

enum class ColorComponents2 {
    RGBA = 42
};

struct RGBA {};
int main () {
    using enum ColorComponents;
    //using enum ColorComponents2;
    // ^ compilation error

    //static constexpr ColorComponents RGBA = ColorComponents(42);
    // ^ compilation error

    struct RGBA x; // Removing "struct" makes this ambiguous
    auto y = (struct RGBA){}; // Removing "struct" makes this ambiguous
    ColorComponents z = RGBA; // Okay

    return (int)RGBA + (int)z;
}

Attempting to use two enums that have the same enumerator name results in a compile error, and theoretically my proposal would work in the same fashion as this makes no sense. Similarly, types can either be disambiguated through a variety of means or, when not properly disambiguated, throw a compile error. Again, theoretically my proposal would work in this way.

Perhaps, but you'd have to actually come up with the rules that make it work "that way."
I infer that you're thinking of a rule something like "For each non-type template parameter of enumeration type, look up all names within the template argument as if they were in a scope preceded by `using enum the-enum-type`." But then you still have problems with overloaded templates, where you don't know whether a given parameter is of enumeration type or not:

    template<ColorComponentLayout, ColorComponents> void f();  // #1
    enum NumberOfBalloons { _99, _8888, _777777 };
    template<ColorComponentLayout, NumberOfBalloons> void f();  // #2
    int main() {
        f<RGBA, _8888>();  // Ambiguous? or unambiguously a call to f #2 with NumberOfBalloons::_8888?
    }

And you have new problems — or at least possibilities-for-confusion ("veridical paradoxes") — with things like:

    enum class E { A,B,C,D,E,F,G };
    template<E> struct S {};
    S<A> s;  // proposed OK, means S<E::A>
    S<(E)-A> s;  // proposed OK, means S<(E::E)-E::A>, not S<(E)-E::A> i.e. S<E(0)>

Modifying the name lookup rules is one of the scariest things you can do in C++-proposal-land.

–Arthur