Date: Mon, 28 Nov 2022 09:39:32 -0500
On Sun, Nov 27, 2022 at 10:05 PM Jason McKesson via Std-Proposals <
std-proposals_at_[hidden]> 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
std-proposals_at_[hidden]> 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
Received on 2022-11-28 14:39:45