I'm trying to call a function with the correct number of parameters in C++14. I have a template class that defines an alias of the itself or void, based on template filters : either the argument is skipped, or passed, something like this :
template<typename comp>
struct exclude {};
template<typename comp>
struct shouldPassComponent
{
using type = comp;
comp& operator()(comp* component) { return *component; }
const comp& operator()(const comp* component) const { return *component; }
}
// void is aliased instead of the component
template<typename comp>
struct shouldPassComponent<exclude<comp>>
{
using type = void;
void operator()(comp* component) {}
void operator()(const comp* component) const {}
}
// if void, the argument should be skipped/not evaluated instead
std::invoke(func, shouldPassComponent<types>()(comps)...); // error here
Unfortunately it doesn't work because the compiler still evaluates "void()" in arguments (error: "no matching overloaded function found").
So I tried the non-template way to see if it would work :
void CallFunction();
CallFunction(void()); // error here
However, the compiler errors with : "error C2672: CallFunction: no matching overloaded function found". So I thought about the fact that lambda accepts auto arguments :
void CallFunction();
auto lambdaTest = [](auto... Arguments)
{
//....
CallFunction(Arguments...);
};
lambdaTest(void()); // error here
Still, the compiler errors with : "error C2672: 'operator __surrogate_func': no matching overloaded function found" when calling lambdaTest. I searched for hours on Internet, and now I'm out of luck.
Is there any way to prevent evaluating/discarding some arguments from a variadic to be passed? Any solution will be appreciated.
I found a solution : https://stackoverflow.com/a/36818808/9142528 it's based on an index sequence which I never thought about. It feeds an index sequence based on a predictate (for each type, puts the index of the type if the predicate for this type has a value of true, nothing otherwise).
template<typename component>
struct exclude {};
template<typename component>
struct isResolvable
{
enum { value = true };
};
template<typename component>
struct isResolvable<exclude<component>>
{
enum { value = false };
};
template<typename...components>
struct view_t
{
template<typename component>
struct component_t
{
using type = component;
};
template<typename component>
struct component_t<exclude<component>>
{
using type = component;
};
template<typename funcType>
static void call(funcType func, typename component_t<components>::type&... comps)
{
callImpl(func, std::make_tuple((&comps)...), find_indices<isResolvable, components...>{});
}
template<typename funcType, typename...components, size_t...Is>
static void callImpl(funcType func, const std::tuple<components*...>& tuple, std::index_sequence<Is...>)
{
std::invoke(func, *std::get<Is>(tuple)...);
}
};
struct test1 {};
struct test2 {};
void testCallback(test1& comp)
{
}
void test()
{
test1 comp1;
test2 comp2;
view_t<test1, exclude<test2>>::call(&testCallback, comp1, comp2);
}