#Retain templated type and self referencing from initializer's lambda

36 messages · Page 1 of 1 (latest)

narrow kilnBOT
#

When your question is answered use !solved to mark the question as resolved.

Remember to ask specific questions, provide necessary details, and reduce your question to its simplest form. For tips on how to ask a good question run !howto ask.

analog ridge
#

Not a very helpful response from me but ... wait till c++23 :D

#

we get "Deducing this" and this is one of the use-cases

#

allows you to get the this pointer in lambdas etc

#

but also this specific case doesnt make sense to me

#
static foo x = +[](int _0, int _1) -> int {
    // x.fn(x, y);
    return 0;
};
#

why would you want to call x.fn(x, y) in this specific case ... because thats the same function that youre already inside, its just going to recurse forever

mystic ridge
#

I don't know what you mean by a and b, so you want to be able to register member functions as well as free functions or what?

#

oh it's that you can't call these other functions mutually, that's the issue

#

then why are they lambdas, if you defined them as a regular free functions, they could call each other just fine if they're forward-declared

#

what is the purpose of reg_fn? you want the function to be reassignable?

#

I don't really get why you need whatever location set_pass stores the function in, and run_pass to be separated

#

well, bar is essentially useless because it's just void* with extra steps

#

I don't really get why this can't just be

struct functions {
    int (*add)(int, int) = [](int a, int b) {
        return a + b;
    };

    int (*mul_2)(int) = [](int x) { return add(x, x); };
};
#

why do you need to both register the function via set_pass and have it be statically stored somewhere else

#

well that's alright, you can re-assign at runtime with

my_functions.D3DCreate = +[]{};

since "D3DCreate" is presumably always a literal and not something computed, it's not very useful for it to be a template argument

#

or maybe it should be an enum class since it seems like there's a limited set of possible functions that are meant to be registered/re-assigned

#

if you don't want macros, I don't see a way of not having at least an if constexpr chain somewhere, like

template <gfx_function F>
auto reg_fn_impl() {
    using enum gfx_function;
    if constexpr (F == gfx_function::D3DCreate)
        return static_cast<int(*)(int, int)>(nullptr);
    else if constexpr (...)
        ...
}

template <gfx_function F>
using reg_fn = decltype(*rg_fn_impl<F>());
#

if you want to call the function pointers from the lambda, you can make all of the members static inline and then they are both reassignable and can call each other

#

;asm

struct functions {
    static inline int (*add)(int, int) = [](int a, int b) {
        return a + b;
    };

    static inline int (*mul_2)(int) = [](int x) {
        return add(x, x);
    };
};
devout islandBOT
#
Compilation successful

No assembly generated.

mystic ridge
#

but at that point you may as well not use a class at all again

#

with this invoker, you still need to provide the return type and arguments explicitly and that's the issue, right?

#

or are they deduced with CTAD from the constructor?

#

ah yes, it is deduced

mystic ridge
#
template <gfx_function F>
using reg_fn = decltype(*rg_fn_impl<F>());

template <gfx_function F>
inline constexpr fn_invoker = invoker(rg_fn_impl<F>());
mystic ridge
#

I guess my suggestion would be to still use macros since you clearly need some lookup tables

#

but what the macros generate could be different, namely using something like a pretty enum technique

#

so

#define LIST() \
    E( D3DFoo, int(int, int) ) \
    E( D3DBar, int(int) ) \

#define E(...) /* stuff */
LIST()

#define E(...) /* stuff */
LIST()

#undef E

and then define E to be whatever and call LIST()

#

@balmy current this could:

  • handle defining all the functions in struct as inline
  • it could handle generating all of the invokers
  • it could handle generating a function containing a switch over a void*/uintptr_t and invoking that as a function with the right function signature
#

if you defined E to be some case, you could make a switch with it

#

so

#define E(name, sig) case static_cast<std::uintptr_t>(functions.name): \
    reinterpret_cast<std::add_pointer_t<sig>>(fn)()
void invoke(void* fn) {
    switch (static_cast<std::uintptr_t>(fn)) {
    LIST()
    }
}
narrow kilnBOT
#

@balmy current Has your question been resolved? If so, run !solved :)

#

Thank you and let us know if you have any more questions!