Home > Enterprise >  Can I pass an array to a lambda such that I can use sizeof()
Can I pass an array to a lambda such that I can use sizeof()

Time:01-31

I'm replacing some #defines with lambdas in my code. I have a bunch of structures which are the result of shader compilation, declared like so:

const BYTE ShaderByteCode[] = 
{
     68,  88,  66,  67, 233, 176, 
     42,  49,  64,  77, 131, 190, 
     75,  97, 214,  59, 236, 203, 
    188, 191,   1,   0,   0,   0, 
    etc...
};

A #define has ShaderByteCode as an input, and calls SetPixelShader, which takes the size of the byte array as a parameter:

#define doThing(Thing, ShaderByteCode) \
Thing.SetPixelShader(ShaderByteCode, sizeof(ShaderByteCode) ); \

Using a lambda, like this:

auto doThing = [](Thing& thing, const BYTE ShaderByteCode[]) {
        thing.SetPixelShader(ShaderByteCode, sizeof(ShaderByteCode));
    };

I will just get a pointer to the start of the array and sizeof() returns the size of the pointer. Is there a way I can pass a single parameter into the lambda, or do I need to do what I'm currently doing and pass the size in separately?

CodePudding user response:

As suggested in comments, maybe a raw array isn't the best thing to pass here.

But you mention a #define macro which does the sizeof. If you want to keep using this because it's the official method of some API, here are some ways to get an array function parameter. The important thing is, a reference-to-array avoids the array-to-pointer decay step.

If you're using C 20, you can do

auto doThing = [] <std::size_t N> (Thing& thing, const BYTE (&ShaderByteCode)[N]) {
    THE_MACRO(thing, ShaderByteCode);
};

If you're using C 14 or later,

auto doThing = [] (Thing& thing, const auto& ShaderByteCode) {
    auto deref_t = std::remove_reference_t<decltype(ShaderByteCode)>;
    static_assert(std::is_array<deref_t>:value &&
                  std::is_same<std::remove_extent_t<deref_t>, const BYTE>,
                  "Invalid argument type in doThing lambda");
    THE_MACRO(thing, ShaderByteCode);
};

If using C 11, or using C 14-C 17 but you need the functor to be SFINAE-friendly, I don't think it can be done with a lambda, but you could define your own functor class with templated operator().

CodePudding user response:

Use template and let template deduction find size of the array:

template<typename T, size_t N>
void doThing(Thing& thing, const T (&shaderByteCode)[N])
{
    thing.SetPixelShader(shaderByteCode, N);
}

No macros, no boiler plate, works with quite old C standard. C will deduce the parameters for you, you do not have to type them explicitly:

Thing thing;
doThing(thing, ShaderByteCode);

some demo.

CodePudding user response:

decltype will be your friend.

If you have whatever C-Style array, decltype will know the number of members.

For example:

using BYTE = unsigned char;
const BYTE ShaderByteCode[] =
{
     68,  88,  66,  67, 233, 176,
     42,  49,  64,  77, 131, 190,
     75,  97, 214,  59, 236, 203,
    188, 191,   1,   0,   0,   0,
    1,2,3
};
using Array = decltype(ShaderByteCode);

Array will be of type const unsigned char[27];

And with that you can pass this element per reference (or pointer) to a function or to a lambda.

This could look like for example this:

#include <iostream>

using BYTE = unsigned char;
const BYTE ShaderByteCode[] =
{
     68,  88,  66,  67, 233, 176,
     42,  49,  64,  77, 131, 190,
     75,  97, 214,  59, 236, 203,
    188, 191,   1,   0,   0,   0,
    1,2,3
};
using Array = decltype(ShaderByteCode);

void SetPixelShader(Array& sbc) {
    std::cout << sizeof(sbc) << '\t' << sizeof(Array) << '\n';
}

int main() {
    auto doThing = [](const Array& SBC) { SetPixelShader(SBC);};
    doThing(ShaderByteCode);
}
  •  Tags:  
  • c
  • Related