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);
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);
}