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.
Related
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).
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'm trying to serialize a templated class MState<T> more or less generically. To do so, I have a parent abstract class MVariable which implements several serialization functions with this form:
template <class Serializer, class SerializedType>
void serialize(Serializer& s, const SOME_SPECIFIC_TYPE &t) const;
I want to allow T to be almost anything. Serialization is done in JSON through RapidJSON::Writer. Because of that, I need to use specific member functions (e.g. Writer::String, Writer::Bool, Writer::Uint...) in order to get the proper formatting for each type T.
Serialization of basic types and STL-containers will be provided by MVariable. However, instead of providing every single type (e.g. replacing SOME_SPECIFIC_TYPE by float, double, bool, etc.) I tried to implement a SFINAE-based solution that seems to have some flaws.
I have a set of typedef definitions and serialization functions like this:
class MVariable
{
template <class SerT> using SerializedFloating =
typename std::enable_if<std::is_floating_point<SerT>::value, SerT>::type;
template <class SerT> using SerializedSeqCntr =
typename std::enable_if<is_stl_sequential_container<SerT>::value, SerT>::type;
/* ... and many others. */
/* Serialization of float, double, long double... */
template <class Serializer, class SerializedType>
void serialize(Serializer& s, const SerializedFloating<SerializedType> &t) const {
s.Double(t);
}
/* Serialization of vector<>, dequeue<>, list<> and forward_list<> */
template <class Serializer, class SerializedType>
void serialize(Serializer& s, const SerializedSeqCntr<SerializedType> &t) const {
/* Let's assume we want to serialize them as JSON arrays: */
s.StartArray();
for(auto const& i : t) {
serialize(s, i); // ----> this fails to instantiate correctly.
}
s.EndArray();
}
/* If the previous templates could not be instantiated, check
* whether the SerializedType is a class with a proper serialize
* function:
**/
template <class Serializer, class SerializedType>
void serialize(Serializer&, SerializedType) const
{
/* Check existance of:
* void SerializedType::serialize(Serializer&) const;
**/
static_assert(has_serialize<
SerializedType,
void(Serializer&)>::value, "error message");
/* ... if it exists then we use it. */
}
};
template <class T>
class MState : public MVariable
{
T m_state;
template <class Serializer>
void serialize(Serializer& s) const {
s.Key(m_variable_name);
MVariable::serialize<Serializer, T>(s, m_state);
}
};
The implementation of is_stl_sequential_container is based on this and the implementation of has_serialize is borrowed from here. Both have been checked and seem to work properly:
MState<float> tvar0;
MState<double> tvar1;
MState<std::vector<float> > tvar2;
rapidjson::StringBuffer str_buf;
rapidjson::PrettyWriter<rapidjson::StringBuffer> writer(str_buf);
writer.StartObject();
tvar0.serialize(writer); /* --> First function is used. Ok! */
tvar1.serialize(writer); /* --> First function is used. Ok! */
tvar2.serialize(writer); /* --> Second function is used, but there's
* substitution failure in the inner call.
**/
writer.EndObject();
However, the recursive serialize call inside the second function, fails to be instantiated. Compiler complains starting with this:
In instantiation of ‘void MVariable::serialize(Serializer&, SerializedType) const
[with Serializer = rapidjson::PrettyWriter<... blah, blah, blah>;
SerializedType = float]’:
The message continues with the static assert error, suggesting that all the previous overloaded template functions failed in their substitutions or that the last one was the best option.
Why is substitution "failing" here for float and not when I try to serialize tvar0 or tvar1?
The problem ...
There are at least two issues in your code.
Firstly, you're explicitly specifying the template arguments in MState::serialize():
MVariable::serialize<Serializer, T>(s, m_state);
but then you're invoking template type deduction inside the SerializedSeqCntr-constrained overload (via serialize(s, i);); this won't work, because those SFINAE checks are non-deduced contexts(*), that is, they do not partecipate in type deduction, the compiler has no way of deducing the SerializedType type.
Either pass the arguments explicitly, as in
serialize<Serializer,std::decay_t<decltype(i)>>(s, i);
or add a deduced SerializedType const& parameter and a sfinae constrained dummy default argument or return type(**).
The second problem is that the 'fallback' overload should precede the constrained overloads possibly invoking it:
template <class Serializer, class SerializedType>
void serialize(Serializer&, SerializedType) const:
template <class Serializer, class SerializedType>
void serialize(Serializer& s, const SerializedSeqCntr<SerializedType> &t);
...
otherwise, name look-up won't find the right serialize() inside the SerializedSeqCntr-constrained overload. Yes, being the function a dependent name, name look-up does happen at instantiation point; however, only names visible in the function body context are considered (unless ADL kicks in).
There could be also a third problem too; the fallback overload is not preferred over the constrained overload just because the former takes SerializedType by value; if this is not the intent, you'll need to further constrain the fallback too.
... and some theory:
(*) to elaborate a bit, when you invoke a function template, you either pass template arguments explicitly (as in foo<bar>()) or let the compiler deduce them from the types of the function arguments (as in foo(some_bar)). Sometimes, this process cannot succeed.
This can happen for three reasons:
there is a substitution failure; that is, a template parameter T has been successfully deduced or given, but it also appears in an expression for which an error would have occurred if spelled out outside the function signature; the function overload is simply ignored; this is what SFINAE is all about.
there is an error while instantiating the types and functions needed to perform substitution; the function is not ignored, the program is ill-formed (if this sounds confusing, this answer may help).
the template argument cannot be deduced, the function overload is ignored; an obvious example is when the template parameter does not appear in any function argument yet is not explicitly specified; another example is when a function argument in which it appears happens to be a non-deduced context, see this answer for an explanation; you'll see that the argument, say, const SerializedFloating<SerializedType>& is indeed non-deduced.
(**) as already said, SFINAE constraints are typically non-deduced; so, if you need type deduction to work, you should pass the to-be-deduced parameter on its own, deducible argument; this is typically done either by adding a dummy default argument or via the return type:
template<typename T>
result_type
foo( T arg, std::enable_if_t<std::is_floating_point<T>::value>* = 0 );
template<typename T>
std::enable_if_t<std::is_floating_point<T>::value, result_type>
foo( T arg );
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.
Just to be sure, from what I've read and tried, I can't put a default argument in a function template correct? I've picked that much up both from my compiler AND from what other's have responded with... I'm asking because I'm a newb and some of the more technical responses are hard to understand. Is there a work around for this? I'm trying to create a findmax function that uses a default relational operator but with the option to overload...ie:
template <typename Type, typename Compare = std::less<Type> >
Type FindMax(std:vector<Type> &vec, Compare comp = Compare()) {
return *std::max_element(...
}
I suppose I could make a class for this but it seems like a lot of work when all I really want is one function... Thanks!
I should add another question as well about something that I've seen before:
What does this function tempate do, specifically, what is the (cmpFn)...) default argument doing?
template <typename ElemType>
ElemType FindMax(Vector<ElemType> &v, int (cmpFn)(ElemType, ElemType) = OperatorCmp)
There are a number of things to say:
What you defined is a function template, not a class template. Since you are using a default template parameter
typename Compare = std::less<Type>
I presume you are already using C++11, because for all I know function templates did not allow default template parameters in the previous versions of the standard.
On the other hand, default arguments of template parameters like this
Compare comp = Compare()
were possible in the previous version of the standard, too. Your statement that default arguments are not possible for templated parameters is wrong (or perhaps it actually referred to what I called default template parameters above).
The compiler error messages that you receive must be due to some other problem. Perhaps the Type you end up using does not go well with std::less, or the Compare type you use does not implement the default constructor. In any case, the following program compiles on GCC 4.6.2 (note that I changed the std::vector<> & to const std::vector<> & because that seemed more right):
#include <vector>
#include <functional>
#include <algorithm>
template <typename Type, typename Compare = std::less<Type> >
Type FindMax(const std::vector<Type> &vec, Compare comp = Compare()) {
return *std::max_element(vec.begin(),vec.end(),comp);
}
int main() {
FindMax(std::vector<int>());
return 0;
}
And indeed this requires the -std=C++0x option, but that is because the default template parameter, not the default argument.
About the extra question related to cmpFn:
That declares a function parameter, i.e. an argument that is itself a function. The declaration
int (cmpFn)(ElemType, ElemType)
means the local name of the function is cmpFn, its return type is int, and it takes two arguments, both of type ElemType. The idea is that the caller can pass a function (or a functor) that will then be used to compare the elements of the vector. E.g. if you define the default value of that argument OperatorCmp before the function declaration like this:
int OperatorCmp(int a, int b) {
return (a<b?-1:(a>b?1:0));
}
the declaration becomes valid and you can use it to find the maximum value of a std::vector<int>.
You can do that in C++11. As of C++03 you can easily work around it by creating two overloads with different number of arguments and forwarding from one to the other.
template <typename Type>
Type findMax( std::vector<Type> const & v ) {
return findMax( v, std::less<Type>() );
}
Alternatively you can use the standard algorithms and avoid having to write your own.