Click here to Skip to main content
15,991,072 members
Please Sign up or sign in to vote.
0.00/5 (No votes)
See more:
Disclaimer: I am targeting embedded, and the STL isn't always available/compliant/responsible on those platforms, so my code doesn't use it at all. Furthermore, I am self taught in this arena so my terminology may be wrong. I will do my best to describe what I want so even if my vocabulary is off kilter hopefully you'll still understand it. I'd ideally like to target C++14, but C++17 is acceptable. No compiler specific extensions are acceptable, nor is any code that may break a particular compiler from a major vendor.

I have a pixel<> template struct, itself composed of one or more channel_trait<> template structs that are passed in via a variadic template argument.

C++
// represents the pixel base class
template<typename... ChannelTraits> 
struct pixel {
    // this type
    using type = pixel<ChannelTraits...>;
...


It has several constructors, some with hateful but unavoidable dummy bool arguments.

C++
// initializes the pixel
constexpr inline pixel() : native_value(0) {
    helpers::pixel_init_impl<type,0,ChannelTraits...>::init(*this);
}
constexpr inline pixel(int_type native_value,bool dummy) : native_value(native_value) {
}
// initializes the pixel with a set of channel values
constexpr inline pixel(typename ChannelTraits::int_type... values) : native_value(0) {
    helpers::pixel_init_impl<type,0,ChannelTraits...>::init(*this,values...);
}
// initializes the pixel with a set of floating point values between 0 and 1.0
constexpr inline pixel(
    bool dummy,
    typename ChannelTraits::real_type... values) : native_value(0) {
    helpers::pixel_init_impl<type,0,ChannelTraits...>::initf(*this,values...);
}


These constructors - two in fact are what are vexing me.

Say I declare a pixel with some padding bits in it that aren't used:

C++
// creates a 24-bit pixel, 6 bits
// unused, the other 18 are RGB666 
// color
using rgb18_pixel = pixel<
    // red channel
    channel_traits<channel_name::R,6>,
    // unused
    channel_traits<channel_name::nop,2>,
    // green channel
    channel_traits<channel_name::G,6>,
    // unused
    channel_traits<channel_name::nop,2>,
    // blue channel
    channel_traits<channel_name::B,6>,
    // unused
    channel_traits<channel_name::nop,2>
>;


This forces me to use 6 values in the constructor, 3 of which are never going to be used for anything (all the ::nop traits)

C++
#define UNUSED 0
rgb18_pixel foo(1,UNUSED,3,UNUSED,5,UNUSED);


Now, it's easy to query each channel_trait to find out if it's an unused channel or not. But what I can't do is get any kind of ::int_type... values off of a subset of ChannelTraits... that only has the used channels.

I can run a separate query to get that, but I can't repack a parameter pack as far as I know?

What I have tried:

I tried swapping out ::int_type for another alias I make ::initializer_int_type

I set it to void for the nop channels. I got a compiler error, so clearly I can't coerce it into dropping those arguments from the constructor that way.

I'm not sure where to go with this? Some kind of templatized ctor?
Posted
Comments
Peter_in_2780 23-Jun-24 22:03pm    
I don't know if this sword can be beaten into a plowshare, but in the good 'ol K&R C days, a bit-field struct could include unnamed (and therefore unreferencable) fields.
K&R 1978 p 138:
...Fields need not be named; unnamed fields (a colon and width only) are used for padding....
honey the codewitch 23-Jun-24 22:04pm    
unfortunately, there's no such corollary with values... here in C++ as the same name is essentially applied to every argument.
honey the codewitch 23-Jun-24 22:06pm    
Oh and as far as me representing pixels as bitfield structs, that's not practical here for a number of reasons.
Josef Schroettle 24-Jun-24 4:15am    
The best way to deal with parameter packs is using std::tuple, you can create a tuple type from the parameter pack type and then filter the tuple type. Later the tuple can be converted back to a parameter pack or used directly. All those operations can be found on stackoverflow. C++17 might be needed...
honey the codewitch 24-Jun-24 4:46am    
Interesting. I did not know it was possible to produce a parameter pack in these versions of C++. That's what I need. I can't use std::tuple but it's using C++ language features so I just need to figure it out.

1 solution

Someone on reddit solved it for me. Not with the constructor though, but this allows me to set multiple channels, by name with one call.

C++
// sets the integer channel value by name
template<typename Name>
constexpr inline void channel(typename channel_by_index<channel_index_by_name<Name>::value>::int_type value) {
    constexpr const int index = channel_index_by_name<Name>::value;
    channel<index>(value);
}
        
// sets the integer channel values by name
template<typename Name1, typename... Names>
constexpr inline void channel(typename channel_by_index<type::channel_index_by_name<Name1>::value>::int_type value1,
                                typename type::channel_by_index<channel_index_by_name<Names>::value>::int_type... values) {
    constexpr const int index1 = type::channel_index_by_name<Name1>::value;
    channel<index1>(value1);
    channel<Names...>(values...);
}
 
Share this answer
 
v2
Comments
Pete O'Hanlon 26-Jun-24 13:12pm    
Well, that's some gnarly voodoo right there. A 5 for adding something else to my arsenal.
honey the codewitch 26-Jun-24 14:24pm    
It makes a surprising amount of sense to me. It's simpler than anything I expected I'd have to do.

This content, along with any associated source code and files, is licensed under The Code Project Open License (CPOL)

  Print Answers RSS
Top Experts
Last 24hrsThis month


CodeProject, 20 Bay Street, 11th Floor Toronto, Ontario, Canada M5J 2N8 +1 (416) 849-8900