My situation
I have two classes, supplied by an external libary not under my control, e.g. their interface is fixed for me.
The first one is a templated 2-D container type, that allows me to manipulate the content held through member functions as well as through raw pointer.
The second one is a class containing a bunch of static member functions that abstract some heavily SIMD-optimized vector operations. Most of them are overloaded to take different datatypes, however they all share a same interface like
VecOperations::op (Type* dest, const Type* src, /* a variable number of operation specific arguments */, int len)
What I want to achieve:
I want to iterate over the first dimension of my 2D container and apply a vector operation to each vector in the second iteration in place. Therefore I want to replace e.g.
auto** ptrs = conatiner.getArrayOfRawPointers();
for (int i = 0; i < container.getXDim(); ++i)
VecOperations::foo (ptrs[i], ptrs[i], arg1, arg2, arg3, container.getYDim());
ideally by something like this (pseudocode)
forAllElements<VecOperations::foo> (container, arg1, arg2, arg3);
This should work for all kind of types stored in my container which are supported by the vector operations classes well as for all numbers of vector operation specific args. To my knowledge writing something like forAllElements above is not possible.
My current solution:
I came up with this instead:
template <typename ElemType, typename ...Args>
struct ForAllElemements
{
template <void(*op)(ElemType*, const ElemType*, Args..., int)>
static void call (Container<ElemType>& buffer, Args... args)
{
auto xDim = container.getXDim();
auto yDim = container.getYDim();
auto** ptrs = conatiner.getArrayOfRawPointers();
for (int i = 0; i < xDim; ++i)
op (ptrs[i], const_cast<const ElemType*>(ptrs[i]), args..., yDim);
}
};
This can be used like
// using a Container<float> and VecOperations::foo (float*, const float*, float, int, float, int)
ForAllElemements<float, float, int, float>::call<VecOperations::foo> (container, arg1, arg2, arg3);
While in C++17 deducing class template arguments from the constructor works, deducing it from a static function call does not work to my knowledge. From my understanding, this is simply not defined, technically I don't see any reason why
ForAllElemements::call<VecOperations::foo> (container, arg1, arg2, arg3);
should be impossible, as all template types can be deduced from the parameters passed to the static function.
So I'm asking you, is there any super clever workaround or pattern I'm not aware of that would make something like this possible with C++17 or also with the later standards?
Class template argument deduction happens only based on an initializer for a class object. Here you don't even want an object of the class type, just to use static member functions.
But backing up, maybe a plain function template can work:
// C++20 will define std::type_identity_t; or just define your own:
template <typename T>
struct type_identity { using type = T; };
template <typename T>
using type_identity_t = typename type_identity<T>::type;
template <typename ...Args, typename ElemType>
void forAllElements(
Container<ElemType> &c,
void (*op)(ElemType*, const ElemType*, type_identity_t<Args>..., int),
Args...);
The function pointer does need to be a function argument here instead of a template argument. This works with plain Args... in the function pointer signature instead of type_identity_t<Args>... if the function is overloaded, but when the function is NOT overloaded, compilers might require the type_identity_t, presumably to make sure Args is in a non-deduced context there. (I think there's an unclear requirement in the Standard causing some different results...)
Note Args can only be deduced from the arguments to forAllElements and not from the function type, and the function type needs to be an exact match. So if you allow those types to be deduced, you'll need to be careful about the exact types of the expressions you pass in. Cast them if necessary. If using literals as constant values, you can use forms like 1.0f to get a float type, etc. Or, you can specify the argument types like forAllElements<float, int, float>, which is why I put ...Args before ElemType in the template (though now ElemType can never be explicitly given and must be deduced from the container argument).
Related
Welcome, this is very rare use-case question.
So, here is what I'm trying to do - lets say I have a variadic template function which takes T ...args and a function type FuncT funcName, so here is what we have so far:
template<typename FuncT, typename ...T>
void myFunction(FuncT (*funcName), T ...args);
Now, I want to store my function at void (*)() (this store functions). This works just fine.
std::deque<void (*)()> functions;
func = functions.front();
func(std::forward<T>(args)...); //args is vardict template argument
Now, I can just pass a function to my function as in:
template<typename FuncT, typename T>
int sharedArgument;
void setArg(int x){
sharedArgument = x;
}
template<typename FuncT>
void myFunction(FuncT funcName){
funcName(sharedArgument);
}
void function(int i){
std::cout << i;
}
int main(){
setArg(5);
myFunction(function);
}
Now, I know this is unnecesary, but i want to present a more complicated problem that im having trouble with.
When i want to store arguemnts, I will probably use std::tuple, its design to store arguments, but
Main question is:
How do i store variable amount of arguments in tuple and then perfectly forward them as normal arguments to some function, so that function receiving
function(std::tupleArgumentsHere...);
will read it as
function(5, 42, "yes", 3.14);
I will use this to store arguments and pass them to std::thread.
Thank you, Cheers.
Use std::apply. It is new in c++17. If you cannot, write your own.
In c++14, make an index sequence the same length as your tuple. Then func(std::get<Is>(std::forward<Tup>(tup))...).
In c++11 do the same thing but write your own index sequence.
std::bind stores the function and the arguments together. It returns a callable object encapsulating a copy of the argument values.
You can also use its "placeholder" facility in case there are additional arguments to add after calling queue.front().
I have the following function
template <typename... Args>
void func(Args&&... args){
// do stuff
}
I now want to create a function pointer, that is callable with a variadic list of arguments, just like the function itself.
template <typename... Args>
using Var_Func = void(*)(Args... args)
At this point, I'm stuck. When creating a variable of type Var_Func, I have to give a list of types for the template:
Var_Func<[List of types]> var_func_p = &func;
This, however, prevents me from calling the pointer with a true variadic list of arguments. I want a pointer, that allows me to call it like a true variadic function, like this:
var_func_p("Test");
var_func_p(0.3, 5);
var_func_p('c', "Another test", 1.3, 3);
I have no idea how to achieve this. Can someone help me?
func isn't actually a function. It's a template that the compiler can use to create new functions when it needs to.
When you do func(5) the compiler creates a function called func<int> and then calls it. When you do func(5.0, 'a') the compiler creates a function called func<double, char> and then calls it. These are two completely different, unrelated functions with two different types.
You can create a pointer to func<int> or func<double, char> or func<> or func<anything else> in the usual way. But you cannot ever create a pointer to func, because func is not a function, it's an instruction for the compiler.
Simply put, this is not possible.
A function template is not a function, it's a template of a function -- and thus it does not have a function pointer until you specify which instantiation you want. At which point, the pointer is fixed to a specific number of arguments of specific types.
It is not possible in the C++ language to type-erase templates into a singular type, such as a pointer that you can pass around and lazily instantiate.
That is, code such as:
some_discrete_variadic_type x = var_func_1;
x(1);
x(1, "2");
x = var_func_2;
x(1);
x(1, "2");
Is not possible, because for type-erasure to work you must normalize the erasure to a fixed number of types (in this case, it would be instantiations).
Depending on what the problem is you are trying to solve, however, there might be workarounds -- though this would require more information.
If your uses are more limited -- such as to pass the functionality into other functions that are only ever known at compile-time, then you can use Functor objects instead and pass them into function templates where the arguments are deduced. For example:
struct var_func
{
template <typename...Args>
auto operator()(Args&&...args) -> void
{
// do something
}
};
Where an example of it being called could be:
template <typename T>
auto consume(T var_func_p) -> void
{
var_func_p("Test");
var_func_p(0.3, 5);
var_func_p('c', "Another test", 1.3, 3);
}
int main()
{
consume(var_func{});
consume(some_other_var_func{});
}
Note that in this case, you're not passing a function template around anymore. You're passing a static object, var_func, which contains a call-operator (operator()) that is a function template.
Like this:
template <typename... Args>
void func(Args&&... args){
// do stuff
}
template <typename... Args>
using f_ptr = void(*)(Args&&...);
int main() {
f_ptr<int,int> p = &func<int,int>;
p(3,1);
}
However, pointers to different instantations of func are incompatible.
This, however, prevents me to call the pointer with a true variadic list of arguments. I want a pointer, that allows me to call it like a true variadic function, like this:
You cannot store a pointer to eg func<double,double> in a f_ptr<int,int>.
template<typename Container, typename Ret, typename ...Args>
struct BindImpl {
template<Ret (Container::*MemberFunc)(Args...)>
class Callable {
public:
inline constexpr Callable (Container *container) :
m_container(container)
{}
inline Ret operator() (Args ...args) const
{
return (m_container->*MemberFunc)(std::forward<Args>(args)...);
}
inline Function<Ret(Args...)> toFunction() const
{
return Function<Ret(Args...)>(*this);
}
private:
Container *m_container;
};
};
template<typename Container, typename Ret, typename ...Args>
BindImpl<Container, Ret, Args...> DeduceImpl (Ret (Container::*)(Args...));
This code is called like this:
(typename decltype(::AIpStack::BindPrivate::DeduceImpl(&EthIpIface::driverSendIp4Packet)) ::template Callable<&EthIpIface::driverSendIp4Packet>((this)).toFunction())
I'm trying to understand what this code does. It apprently is a way to bind function pointers (like &EthIpIface::driverSendIp4Packet) to something.
The line above is from this macro, which fills this struct member, if anyone is intersted. You may wanna have a loot at Function.
The first part that I don't understand is
template<Ret (Container::*MemberFunc)(Args...)>
For me a template must be followed by typename. Also, what follows typename, is the thing to be substituted for. I don't see how this template makes Callable templated. I don't know where something goes to in Callable<something>.
Also, what is DeduceImpl? Looks like a function declaration but without a definition.
Also, what Container::*MemberFunc means?
Firstly, templates can also take in non-type parameters as well as with typename and class. In this case:
template<Ret (Container::*MemberFunc)(Args...)>
This is a template taking a function pointer as a parameter, where Ret is the return type, Container::*MemberFunc is the pointer to a specific member function in Container with Args... referencing variadic arguments. This gives the pointer the identifier MemberFunc. I have a feeling the asterisk following the scope resolution operator confused you, as usually you would receive a compiler error if you used these two together in any other situation but in this specific case these two are considered one token ::* representing this kind of template parameter instead of the two :: and *.
For this line:
BindImpl<Container, Ret, Args...> DeduceImpl (Ret (Container::*)(Args...));
It is a function declaration. This is a function named DeduceImpl that will return a BindImpl struct that takes a function pointer as an argument. I'm inferring that this function is the interface by which you bind the function pointer, hence the (probably) shortened names "Deduce Implementation" and "Bind Implementation" From what I've read, this function is only used for decltype, so there's no actual definition for this function.
For how this template is actually being utilized in this line (reformatted for easier reading):
typename decltype(::AIpStack::BindPrivate::DeduceImpl(&EthIpIface::driverSendIp4Packet))
::
template Callable<&EthIpIface::driverSendIp4Packet>(this).toFunction()
This is a template disambiguator created just so the compiler knows that the actual template is being utilized instead of a less-than comparison operator.
You wouldn't write all of this just to use the template. This line was probably written because it's one of the few ways the template is instantiated in the project.
In summary:
template<Ret (Container::*MemberFunc)(Args...)> is a template that takes a function pointer referred to as MemberFunc as a parameter.
DeduceImpl returns a BindImpl struct by taking in the function pointer you want to bind.
I am trying to write a general invocation function.
It has the following syntax:
template<int Index, typename ReturnType, typename... Parameter>
ReturnType invokeGlobalFunction(Parameter... parameters)
{
return invocator->invoke<ReturnType>(Index, parameters...);
}
Next, I try to derive two different function points from it, like this:
registerFunction(::someGlobalFunction, &invokeGlobalFunction<0, void>);
registerFunction(::someOtherFunction, &invokeGlobalFunction<1, int>);
Where someGlobalFunction has the prototype void someGlobalFunction() and someOtherFunction has the prototype int someOtherFunction(int, const char *).
On the first call, it works like a charm, however the second call throws the error: candidate template ignored: deduced conflicting types for parameter 'Parameter' (<int, const char *> vs. <>).
This implies, that the compiler (g++ 7.4.0 on an Ubuntu system btw.) does not overload the invokeGlobalFunction with the different parameter sets like I expected him to.
A note: When I explicitly set the parameter types on the call
registerFunction(::someOtherFunction, &invokeGlobalFunction<1, int, int, const char *>);
the compiler happily takes it, but I'd like to avoid that, if possible.
As a bonus, it would be great, if I could somehow create a unique function each time the index changes, because that would allow me to have functions with identical parameters but differing return types (which is illegal as far as I know).
Thank you.
but I'd like to avoid that, if possible.
Not with template functions, as far I know.
The problem is that a template parameter isn't a single object but a set of object where a function can accept only an object from the set.
When you write
&invokeGlobalFunction<1, int>
you choose a precise function with Index = 1, ReturnType = int and (this is the point) an empty Parameter... list.
Suggestion: if you can, transform invokeGlobalFunction() in a template struct with a template method.
Something as
template <int Index, typename ReturnType>
struct invokeStruct
{
template <typename ... Parameters>
ReturnType operator() (Parameters ... parameters)
{
// ...
}
};
This way you have a set of struct with, in every struct, a set of operator() in it; passing a invokeStruct<1, int>{} as argument, you pass a single object but, inside it, you have available a set of method.
I have a template class with a callable type-parameter <typename Callable>.
I know that Callable indeed creates a callable object, and is often a lambda.
In my particular case, I also know the number (arity) and type of arguments (just one).
How can I get the return type of this callable type Callable on VS2010?
See std::result_of.
Pretending the object is invoked with one int argument, you could do things like:
using return_type = typename std::result_of<Callable(int)>::type;
This isn't generally possible.
There are multiple ways to have callable types, including lambdas and structs that overload operator().
C++ does not have nearly the type of reflection that languages like C# do, and it is impossible to do with the tools that C++ offers.
If all you want is to store the result of that "callable" into a variable, then you can just use auto.
If you actually want to do stuff with the result based on its type, then this question might help.
Basically, add this to your code.
template <typename T, typename U>
struct same_type
{
static const bool value = false;
};
template <typename T>
struct same_type< T, T >
{
static const bool value = true;
};
Then, if you have auto result = func(param);, where func is of type Callable, you can check the type of result with the following:
if (same_type<decltype(result), int>().value)
{
// code, knowing that result is of type int
}
else if (same_type<decltype(result), const char*>().value)
{
// code, knowing that result is of type const char*
}
// else if ... etc.
I tried various approaches, but support for C++11 in VS2010 is only partial and most approaches simply didn't compile.
What did finally work (on VS2010) is the following:
// When arity is known
typedef decltype(callbackInstance0()) return_type0;
typedef decltype(callbackInstance1(argInstance)) return_type1;
Where callbackInstanceX is the actual callable object to be used and argInstance is the actual arg to be passed to callbackInstance.
Note that this is not a general solution (though sufficient in my case) because:
It cannot be used outside of a function where you don't have actual instances of these types, but only the types, as in the class definition;
The callable arity must be known.