Sending a templated function as an argument to a templated function in D - templates

I'm trying to send D's sort function as a template argument to the pipe function. When I use sort without template arguments it works:
import std.stdio,std.algorithm,std.functional;
void main()
{
auto arr=pipe!(sort)([1,3,2]);
writeln(arr);
}
However, when I try to use sort with a template argument:
import std.stdio,std.algorithm,std.functional;
void main()
{
auto arr=pipe!(sort!"b<a")([1,3,2]);
writeln(arr);
}
I get an error - main.d(5): Error: template instance sort!("b<a") sort!("b<a") does not match template declaration sort(alias less = "a < b",SwapStrategy ss = SwapStrategy.unstable,Range)
Why does it happen? sort!"b<a" works on it's own, and it has the same arguments and return types as sort, so why does pipe accept sort but not sort!"b<a"? And is there a correct syntax for what I try to do?
UPDATE
OK, I've tried to wrap the sort function. The following code works:
import std.stdio,std.algorithm,std.functional,std.array;
template mysort(string comparer)
{
auto mysort(T)(T source)
{
sort!comparer(source);
return source;
}
}
void main()
{
auto arr=pipe!(mysort!"b<a")([1,3,2]);
writeln(arr);
}
So why doesn't the original version work? is this because of the extra template parameters sort takes?

Yes it's because of the extra template parameters — specifically the Range parameter. The problem can be reduced to
size_t sort2(alias f, Range)(Range range)
{
return 0;
}
alias sort2!"b<a" u;
The instantiation sort!"b<a" will fail because the Range is not determined. The function call sort2!"b<a"([1,2,3]) works because the parameter [1,2,3] can tell the compiler the type Range is int[]. This is known as "implicit function template instantiation (IFTI)". But IFTI only works when it is used as a function. In your use case, sort!"b<a" is instantiated without providing all parameters, thus the error.
This can be fixed by making the input a function literal, which is just similar to your mysort solution:
auto arr = pipe!(x => sort!"b<a"(x))([1,3,2]);
Or you could provide all required template parameters. This makes the code very unreadable though.
auto arr = pipe!(sort!("b<a", SwapStrategy.unstable, int[]))([1,3,2]);

Related

Function pointer to member function T(U) where T and U may or may not be void

I have a class Frobnicator that handles various requests.
class Frobnicator
{
public:
// Handlers are member functions.
// They optionally take some input. They optionally return some output. But they always take the context!
// There are more types than just int involved, but it's always just one input or void, and one output or void.
void performSomething(Context* context) { /* ... */ } // Takes void, returns void
void setSomething (Context* context, int input) { /* ... */ } // Takes int , returns void
int getSomething (Context* context) { /* ... */ } // Takes void, returns int
int convertSomething(Context* context, int input) { /* ... */ } // Takes int , returns int
template<typename TResult, typename TParameter>
void registerHandler(std::string identifier, TResult(Frobnicator::* handler)(Context*, TParameter))
{
// The external API actually wants a callback that takes and returns JSON. We give it a lambda that does the conversion and calls the actual member function.
// The identifier tells the external API which callback to call for which request. It's not relevant for this question, just to show the idea. Think of something like a REST API.
someExternalApiThatWantsJson.registerHandler(identifier, [&](Context* context, Json input)
{
// Idealy, this would be a one-liner.
//return Json::convertFrom((this->*handler)(context, input.convertTo<TParameter>()));
// But calling Json.convertTo<void>() and Json::convertFrom(void) does not work automagically anyways, so we need to split it up manually:
Json result;
if constexpr (std::is_same<TResult, void>::value)
if constexpr (std::is_same<TParameter, void>::value) (this->*handler)(context ) ; // Takes void, returns void
else (this->*handler)(context, input.convertTo<TParameter>()) ; // Takes something, returns void
else
if constexpr (std::is_same<TParameter, void>::value) result = Json::convertFrom((this->*handler)(context )); // Takes void, returns something
else result = Json::convertFrom((this->*handler)(context, input.convertTo<TParameter>())); // Takes something, returns something
return result;
});
}
// Set up the handlers.
void setup()
{
// The problem is that some of these calls don't work:
registerHandler ("PerformSomething", &Frobnicator::performSomething); // "failed template argument deduction"
registerHandler<void, void>("PerformSomething", &Frobnicator::performSomething); // Trying to specify the types explicitly: "substitution failure [with TResult = void, TParameter = void]: argument may not have 'void' type"
registerHandler ("SetSomething" , &Frobnicator::setSomething); // Compiles fine
registerHandler ("GetSomething" , &Frobnicator::getSomething); // "failed template argument deduction"
registerHandler<int , void>("GetSomething" , &Frobnicator::getSomething); // Trying to specify the types explicitly: "substitution failure [with TResult = int, TParameter = void]: argument may not have 'void' type"
registerHandler ("ConvertSomething", &Frobnicator::convertSomething); // Compiles fine
}
};
TResult can be int or void and it works fine. But it only works when TParameter isn't void.
How can I make registerHandler also accept pointers to functions that take no arguments?
The idea is to have the member functions' signatures very clean and the calls to registerHandler mostly clean. So giving performSomething and getSomething a dummy parameter is out of the question. Manually specifying the types when calling registerHandler is ugly but I'll accept it, if it's necessary.
The body of registerHandler is relatively short and mostly deals with distinguishing void from non-void anyways, so providing a specialization for when TParameter is void would be a fine solution:
template<typename TResult>
void registerHandler<TResult, void>(std::string identifier, TResult(Frobnicator::* handler)(Context*))
Except that "function template partial specialization is not allowed".
Use template parameter pack to deal with void / non-void cases, since the number of arguments is indetermined (1 or 2).
template<typename TResult, typename... TParameter>
void registerHandler(std::string identifier, TResult(Frobnicator::* handler)(Context*, TParameter...))
The second parameter accepts a pointer to member function whose the first argument is required to be Context*, that's it.
Then,
void setup()
{
registerHandler ("PerformSomething", &Frobnicator::performSomething);
registerHandler ("SetSomething" , &Frobnicator::setSomething);
registerHandler ("GetSomething" , &Frobnicator::getSomething);
registerHandler ("ConvertSomething", &Frobnicator::convertSomething);
}
The implementation of registerHandler may also need some changes, the std::is_same_v<TParameter, void> can be replaced by sizeof...(TParameter) == 0.
Demo
Well. Sometimes you waste an hour because you narrowly miss a solution. Just don't make it a specification:
template<typename TResult>
void registerHandler(std::string identifier, TResult(Frobnicator::* handler)(Context*))
But!: This is a valid solution for me, but it would be nice to have a solution that does not require duplicating almost the entire function body. So better answers are absolutely welcome!
What I would do is follow the 0 1 infinity rule and write infinity instead of 2 cases.
Support any number of arguments. Map to tuples. Empty tuples for 0, mono for 1, etc.
Then the conversion code should work naturally. You can bind the call to be (take tuple, return tuple), then write the input/output code to handle 0, 1, or n from/to json.
Now the json function call logic no longer cares about void. The packing unpacking does. And the code that calls the raw function from tuples and packs it into a tuple return does.
template<class F>
auto packresult(F&&f){
if constexpr(f() is void)
f()
return tuple<>{};
else if constexpr(f returns a tuple)
return f();
else
return std::make_tuple(f());
}
Now you do the same for inputs
auto unpackargs(auto&&f){
return [f](auto&&tup){
return std::apply(f, tup);
}
}
which makes your code look like:
converttupletojson(packresult(bind(unpackargs(bind this to method), getargsfromjson<Args...>())))
and viola, the most surprising musical instrument.

How to rewrite template function to allow code reuse

Consider the following template recursion function. Its purpose is to create a vector containing all values in the enum class EnumClassName for which its associated predicate function bool xxx<N>() returns true.
template <EnumClassName N = EnumClassName::LAST_ENUM_VALUE>
std::vector<EnumClassName> xxx_stuff()
{
std::vector<EnumClassName> v = xxx_stuff<EnumClassName(static_cast<int>(N) - 1)>();
if (xxx<N>()) {
v.emplace_back(N);
}
return v;
}
with the recursion base case:
template <> std::vector<EnumClassName> xxx_stuff<EnumClassName::FIRST_ENUM_VALUE>()
{
return {};
}
Now assume there are 10 of these functions where the only thing that differs is the xxx name. I.e. we have the functions alpha_stuff with a corresponding predicate function alpha<N>, beta_stuff with a corresponding predicate function beta<N>, etc etc.
Is there any way to not duplicate the above function 10 times, where the only difference is the replacement of xxx with alpha, beta etc in each duplicate?
I am not able to just loop over the enum values, because the xxx<N> functions in turn call another function yyy<N> which will not accept a runtime-generated template argument <N> (forgive my lingo there, I actually have no idea what I'm talking about or how this works, I just know it gave me compilation errors when I tried it that way).
You cannot pass function template as argument or overloaded function, but you can wrap the call in a type, and then
template <typename EnumClassName,
EnumClassName N = EnumClassName::LAST_ENUM_VALUE,
typename F>
std::vector<EnumClassName> xxx_stuff(F&& f)
{
std::vector<EnumClassName> v =
xxx_stuff<EnumClassName, EnumClassName(static_cast<int>(N) - 1)>(f);
if (f(std::integral_constant<EnumClassName, N>{})) {
v.emplace_back(N);
}
return v;
}
with usage
auto v = xxx_stuff<E>([](auto n) { return xxx<n()>(); });
Demo
Note: That recursion can be avoided using std::integer_sequence.

Fold expression has empty expansion

I have some very heavily templated code, where I need to pass configuration flags encoded as unsigned via a template.
template<unsigned T>
struct MemoryTraits
{
// Do something with T...
};
There are some predefined flags, that I'm supposed to bit-or, and pass to the struct above, then it will be passed further to other templated functions and classes.
SomeTemplatedContainer</*other parameters */, MemoryTraits<Trait1 | Trait2>> myContainer{};
I was trying to create a variadic template function, that would take any number of flags, and alias the MemoryTraits, depending on template parameters.
template<unsigned ...Traits>
void foo() {
using MyMemoryTraits = MemoryTraits<(Traits | ...)>;
SomeTemplatedContainer</*other parameters */, MyMemoryTraits> myContainer{}
}
I tried to implement it using c++17 fold expressions, and everything works when I invoke foo with one or more arguments, but when calling it without any, I get the following compile time error.
error: expected expression
foo(); -> fold expression has empty expansion
From what I understand, it's because an empty fold expression with operator | doesn't have a default value, is there any way I can provide a default value to it? So far I came up with the following helper lambda.
constexpr auto TraitsHelper = [](){
if constexpr (sizeof...(Traits) == 0){
return 0;
} else if constexpr(sizeof...(Traits) == 1){
constexpr std::array TRAITS{Traits...};
return TRAITS[0];
} else {
return (Traits | ...);
}
};
It works, at least for now, but is there some better way to fix this issue?

transform each element of tuple; get that tuple

I have a tuple in D. I want to apply an element-wise operation on that tuple, and get that transformed tuple for passing into another function that accepts variadic template arguments. The execution path of the transform is defined at compile time, but the actual value is not.
The purpose of this is similar to the template mechanism used in C++'s bind construct, for determining where to use placeholders/passed arguments and where to use stored arguments at compile time.
How do I accomplish this?
this is the first time in D I've ever missed a feature in C++11's template system: the pack/unpack operator - please make me not feel bad :-(
EDIT: Ended up using mixins, because apparently any generic programming solution you want can be solved by using them. May answer with them if no one comes up with anything more elegant than taking D's ridiculously powerful jackhammer-of-a-generic-programming-tool to it.
The element of a tuple can be anything that a template alias parameter can be. However, run-time expressions cannot be alias parameters - they are evaluated at compile time. Thus, it is not possible to transform a tuple using a transformation that runs at compile-time (barring workarounds such as where the transformation defines a #property function that returns the result).
If the expression and transformation can be evaluated at compile-time, see staticMap from std.typetuple.
If I understand the question right, then this is possible but it's a highly experimental (undocumented and not guaranteed to always work) feature:
import std.stdio;
import std.traits;
import std.typetuple;
ReturnType!Call Delay(alias Call, alias arg)() { return Call(arg); }
template Map(alias Call, args...)
{
static if (args.length > 1)
alias Map = TypeTuple!(Delay!(Call, args[0]),Map!(Call, args[1..$]));
else
alias Map = Delay!(Call, args[0]);
}
int square(int arg)
{
return arg * arg;
}
void print(int res1, int res2)
{
writefln("%s %s", res1, res2); // writes '25 100'
}
void test(Args...)(Args args)
{
print(Map!(square, args));
}
void main()
{
int x = 5;
int y = 10;
test(x, y);
}
Originally asked here: Mapping variadic template arguments in D

how to solve following problem in C++?

I have one template function which will take a pointer type and i have instantiated it before calling.
i have written function with its dummy implementation as follows:
template<T>fun_name( const T *p )
{
//written functionality which will give me class name that i will store into string Variable
e.g. i got output like this string Var = "First_class" or string Var = "Second_class"
//Using this class name i will call one function of that class
if(Var == "Fisrt_class")
{
First_class::static_function_name(p);
}
if(Var == "Second_class")
{
Second_class::static_function_name(p);
}
}
and in global scope i instantiated this function for two variables as like below:
template<first_class>static_function_name(const First_class *)
template<Second_class>static_function_name(const Second_class *)
above code gives me error that
error: no matching function call in Second_class::static_function_class(const Fisrt_class*)
error: no matching function call in First_class::static_function_class(const Second_class*)
thanks in advance!
I think this :
template<typename T> // template<class T> is equally valid!
void fun_name( const T *p )
{
T::static_function_name(p);
}
is enough!
Two more errors is fixed in the above code:
Mention the keyword typename in template<T> in your code. You can also write template<class T> which is equally valid.
Mention the return type of the function template as well.
Your function template "calls" each of the static functions in each class. Even though program flow may never get to one of the calls, the compiler still has to figure out the code for each of them.
So when you instantiate:
template<first_class>fun_name(const first_class*)
the compiler tries to compile the entire function with T = first_class, which means at some point inside the function, it will try to compile the function call:
Second_class::static_function_name(p);
But since variable p is a pointer to first_class, the compiler doesn't find the function.
If you want conditional compilation, try specializing your function instead so the compiler only compiles the function call you intended for each type:
template <T> fun_name (const T* p);
template <> fun_name<first_class>(const first_class* p) {
first_class::static_function_name(p);
}
template <> fun_name<second_class>(const second_class* p) {
second_class::static_function_name(p);
}
Alternatively, you can use member functions which seem to be intended for what you are trying to do here. Then you can create objects and call the functions directly:
first_class f;
second_class s;
f.function();
s.function();
try changing to ,
template<typename T>
void fun_name( const T *p )
{
T::static_function_name(p);
}