On Sun, Nov 27, 2022 at 10:05 PM Jason McKesson via Std-Proposals <std-proposals@lists.isocpp.org> wrote:
On Sun, Nov 27, 2022 at 8:40 PM Ryan Klaus via Std-Proposals wrote:
>
> Let's say I have a template class that takes two enums:
>
> template <ColorComponents T_components, ColorComponentLayout T_layout>
> class Color { ... };
>
> Because I'm a good boy, each enum is of course an enum class like so:
>
> enum class ColorComponentLayout {
>     _332,
>     _4444,
>     ...
> };
>
> enum class ColorComponents {
>     RGB,
>     RGBA,
>     ARGB,
>     ...
> };
>
>
> And all of the above is inside the namespace "ABC".
>
> In a just world, I feel like I should be able to write something like this:
>
> auto color = ABC::Color<RGBA, _8888>{};

You'd have to explain why this should look up _8888 in the scope of `ABC`, instead of in the current scope.
For example,
    int main() {
        static constexpr ABC::ColorComponents _8888 = ABC::ColorComponents(42);
        auto color = ABC::Color<RGBA, _8888>();  // isn't _8888 in this scope a synonym for 42, not ABC::ColorComponents::_8888?
    }
This will make your proposal vastly more complicated than you initially thought.

Also, remember that function templates can be overloaded:

    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?
    }

Finally, what I initially thought Jason was getting at with his comment (but now I don't see it anymore), you'd have to consider what to do with this case:

    auto k = std::integral_constant<ABC::ColorComponents, _8888>;  // Does this mean ABC::ColorComponents::_8888?

In general, C++ doesn't do "context-dependence." It's not like Perl, where functions can behave differently when called in "scalar context" versus "array context." The one feature C++ has that works "in the backwards direction" is braced-initializer-lists, and even that was a mistake from the teachability perspective. Let's not add any more.

In practice, the simplest way for you to achieve terseness here would be with a macro. Any time you find yourself repeating a snippet over and over, you should consider whether it makes sense to factor it out — as a function, as a template, as a macro, or whatever. The macro preprocessor is basically the backstop that allows you to factor out anything, regardless of what name lookup or overload resolution or even the language grammar might think of it.

    #define ABC_COLOR(x, y) ABC::Color<ABC::ColorComponentLayout::x, ABC::ColorComponents::y>()

    auto color = ABC_COLOR(RGBA, _8888);  // This is valid C++20 syntax, and valid C++11 syntax as well

HTH,
Arthur