Parameters after parameter pack in function [duplicate] - c++

This question already has answers here:
Variadic function template with pack expansion not in last parameter
(4 answers)
Closed 6 years ago.
I was able to find one question on SO that seems to be asking the same or similar question that I am, but there are no answers :-(
I'd like to place a non-template parameter after a parameter pack. I'm not too familiar on the C++ standard specification for variadic templates / parameter packs, but my common sense assumption tells me that the right-most parameters passed to a function would be filled into placement parameters first, then the rest get filled into the parameter pack. However, I'm not able to get my test code working on either g++ or clang++. Sample code below.
#include <vector>
#include <iostream>
int Subscribe(int channel, int callback)
{
return channel;
}
// This one works fine...
template<typename... T>
std::vector<int> SubscribeMultiple1(int callback, T&&... channels)
{
return {
Subscribe(std::forward<T>(channels), std::move(callback))...
};
}
// This one does not work; all I did was move `int callback` after the parameter pack.
template<typename... T>
std::vector<int> SubscribeMultiple2(T&&... channels, int callback)
{
return {
Subscribe(std::forward<T>(channels), std::move(callback))...
};
}
int main()
{
auto subs = SubscribeMultiple2(1, 2, 3);
for (auto sub : subs)
{
std::cout << "Sub: " << sub << '\n';
}
}
Live Sample
So my first question is, why does the non-template parameter not work after the parameter pack? Am I doing something wrong or is this prohibited by the language?
Secondly, is there any way to get the syntax I'm trying to do? I've oversimplified my sample, but in my real code the callback parameter is really a std::function<...>. The idea is I can subscribe to a number of "event IDs", and the callback is defined at the end. Having the callback at the end is better for readability and style. Example:
SubscribeMultiple(EventOne, EventTwo, EventThree, [] {
// Implement callback code here when any of the above
// three events are fired.
});
If I have to have the callback in the front, it's less readable IMHO. So I'm willing to try any workaround to get the syntax and structure I'm aiming for. Thanks in advance.

Am I doing something wrong or is this prohibited by the language?
Deduction of parameter packs occurs only when the pack is the last argument.
[temp.deduct.type]/5.7:
The non-deduced contexts are:
[...]
A function parameter pack that does not occur at the end of the parameter-declaration-list.
So that's normal behavior of standard C++.
is there any way to get the syntax I'm trying to do?
Use the first syntax as a workaround:
template<typename... T>
std::vector<int> SubscribeMultiple1(int callback, T&&... channels)

Related

Is there a way to dynamically change the return-type of a function in C++ based on function parameter values?

I am working on a problem that requires me to return different return-types based on my function parameter values that I provide.
I want to do something like this --
In the code below, doSomething() is an already existing function (used by a lot of clients) which takes mode as a function parameter, and returns std::list<ReturnType> already.
Based on the mode value, I had to create another sub-functionality which returns a shared_future<std::list<ReturnType>>.
How can I change this code so that it can return one of the two return types based on the mode value?
Note: ReturnType is a template typename which we are using for the entire class.
Code:
std::shared_future<std::list<ReturnType> > futureValue() {
return functionReturningSharedFuture();
}
std::list<ReturnType> listValue() {
return functionReturningList();
}
std::list<ReturnType> doSomething(int mode) {
if(mode == 1){
// new functionality that I added
return futureValue(); // This (obviously) errors out as of now
}
else{
// already there previously
return listValue();
}
}
int main() {
doSomething(1);
return 0;
}
How can I change this code so that it can return one of the two return types based on the mode value?
Constraints and Issues:
This issue could've been easily solved by function overloading if we provide an extra function parameter (like a true value), but that extra argument is not useful, since we are already using mode. Also, it isn't considered a good design to add variables which have almost no use.
One of the major constraints is that there are clients who are already using this doSomething() expect a std::list<ReturnType>, and so I cannot return boost::any or std::variant or anything similar.
I tried using std::enable_if, but it wasn't working out since we are getting the mode value at runtime.
We can't use template metaprogramming since that would change the way our function is being called on the client-side. Something that we can't afford to do.
Thank you.
This cannot be done.
You can only have one function with a given signature. If you have calling code that already expects this to return a std::list<ReturnType>, that's it; you're done.
If you could guarantee that all existing calling code looks like
auto l = obj.doSomething(1);
then you could potentially change the return type to something which would look like a std::list to any calling code. But if there's any calling code that looks like
std::list<ReturnType> l = obj.doSomething(1);
then that's off the table.
You probably need to rethink your design here.
From the example main, I see doSomething(1);, so maybe at the call site the value of the parameter mode is always known at compile-time. In this case, one option is that you make doSomething a template<int mode> function. I'm thinking about something like this:
#include <iostream>
#include <list>
#include <vector>
// assuming you cannot change this (actually you have changed it in you example, ...)
std::list<int> doSomething(int mode) {
std::cout << "already existing function\n";
return std::list<int>{1,2,3};
}
// then you can put this too
template<int N>
auto doSomething();
template<>
auto doSomething<10>() {
std::cout << "new function\n";
return std::vector<int>{1,2,3};
}
int main() {
auto x = doSomething(3);
auto y = doSomething<10>();
}
Probably another option would be to use a if constexpr intead of if and an auto/decltype(auto) return type in doSomething, but I haven't tried it.

Passing lambdas as a parameter in C++

I am trying to generalize my benchmarking function, by having it receive the function to benchmark as the first parameter and the number of iterations as the second.
But since the function to benchmark needs to receive additional parameters, I thought I would fill in the parameters in the body of a lambda function and pass that to the benchmarking function. (I think that is called currying?)
Anyway I can not get it to compile:
main.cpp:43:62: error: invalid initialization of non-const reference of type ‘std::function<double*()>&’ from an rvalue of type ‘main(int, char**)::<lambda()>’
bench::bench([=](){rng::gpu_r_exp((int) 10e6, lambda);}, 50);
The function declaration looks like this:
void bench(std::function<double*()>& funct_to_bench, int repeats);
and I use it like this:
bench::bench([=](){rng::gpu_r_exp((int) 10e6, lambda);}, 50);
Since the compiler bickers about non-const again, I should maybe add, that gpu_r_exp utilizes a global variable which stores the rngState (it also did not like non-const parameters in gpu_r_exp).
I am really stuck. I just want to fill in the parameters and pass the pre-prepared function handle to the benchmarking function, so that it can wrap a timer with a progress bar around it.
EDIT: I should add that the parameter called lambda is a double, which is the parameter of the exponential distribution and has nothing to do with the lambda function.
Given that the benchmark wrapper is small, it doesn't make sense to worry about what's passed in, or whether it can be converted to std::function. Just take what comes and as long as it can be called, you're golden:
template <typename Fun>
void benchmarkCallable(size_t iterations, Fun &&callable)
{
//...
while (iterations--)
callable();
//..
}
If you worry that the //... sections are getting unwieldy, you can factor them out into a class:
class ScopedBenchmark {
// start time, other state needed, etc.
public:
ScopedBenchmark() { /* capture initial state */ }
~ScopedBenchmark() { /* dump results etc */ }
};
template <typename Fun>
void benchmarkCallable(size_t iterations, Fun &&callable)
{
ScopedBenchmark benchmark;
while (iterations--)
callable();
}
int main()
{
benchmarkCallable(1'000'000, []{ printf("foo!\n"); });
}

Correct usage of `for_each_arg` - too much forwarding?

I'm really happy to have discovered for_each_arg(...), which makes dealing with argument packs much easier.
template<class F, class...Ts>
F for_each_arg(F f, Ts&&...a) {
return (void)std::initializer_list<int>{(ref(f)((Ts&&)a),0)...}, f;
}
I'm, however, confused on its correct usage. There are many arguments that need to be perfectly forwarded, but am I performing any unnecessary forwarding?
Reading the code becomes harder with excessive fowarding.
struct UselessContainer
{
// Expects a perfectly-forwarded item to emplace
template<typename T> void add(T&&) { }
};
// Creates an `UselessContainer` already filled with `mArgs...`
auto makeUselessContainer(TArgs&&... mArgs)
{
using namespace std;
UselessContainer result;
for_each_arg
(
[&result, &mArgs...] // Am I capturing the `mArgs...` pack correctly here?
(auto&& mX) // Am I passing the arguments to the lambda correctly here?
{
// Is this `forward` necessary?
result.add(forward<decltype(mX)>(mX));
// Could it be replaced with
// `result.add(forward(mX));`
// ?
},
forward<TArgs>(mArgs)... // I assume this `forward` is necessary.
);
return result;
}
All my questions/doubts are expressed in the comments in the above code example.
Every forward in your code is indeed necessary to perfectly forward all arguments until the end. Names of rvalue references are lvalues, so unless you're forwarding everytime you pass arguments on, the value category information is lost.
Also it is impossible to call forward without an explicit template argument list as the template parameter is only used in one, non-deduced context. In fact, a function template called without an explicit argument list cannot do the job.
You can try a macro to somewhat shorten the code:
#define FORWARD(...) std::forward<decltype(__VA_ARGS__)>(__VA_ARGS__)
It then becomes
for_each_arg
(
// Removed superfluous capture
[&result] (auto&& mX) {
result.add(FORWARD(mX));
},
FORWARD(mArgs)...
);
It's also possible to use a macro instead of for_each_arg in the first place:
#define FOR_EACH_ARG(...) (void)std::initializer_list<int>{((__VA_ARGS__),0)...}
FOR_EACH_ARG( result.add(forward<TArgs>(mArgs)) );
for_each_arg (
[&](auto&& mX){
result.add(std::forward<decltype(mX)>(mX));
},
std::forward<TArgs>(mArgs)...
);
Just capture & when making this kind of lambda. If you must list, only &result need be captured.
forward<?> is always used with a type parameter.
Note Eric's for_each_arg is imperfect, and mostly about doing it in 140 characters or less. ;) Its imperfections are mild, and harmless here.
Here is an alternative:
First, write this:
template<class...Fs>
void do_in_order(Fs&&...fs){
int _[]={0,
(((void)(std::forward<Fs>(fs)())),0)...
};
(void)_; // kills warnings
}
it takes zero arg lambdas, and runs them left to right.
Then replace the call to for_each_arg with:
do_in_order(
[&]{
result.add(std::forward<TArgs>(mArgs));
}...
);
the downside is that more compilers won't like the above.
Ordering of the expressions in the do_in_order is guaranteed by [dcl.init] and [dcl.init.list] sections in n4296 8.5.4/4 8.5.4/1 8.5/15 8.5/1. The initialization is a copy-list-initialization (8.5/15 and 8.5.4/1), is a "initializer-list of a braced-init-list" (8.5/1) and as such is sequenced left to right (8.5.4/4).

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

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]);

Wrapping any API Function

I'm wrapping the Windows API, and I wish to make error checking easy to use, and helpful. Currently, I have a global error object, with a function set to handle a new error. The set function takes four arguments: bool Error::set (const int code, const char * file, const char * const function, const int line); The function uses the file, function, and line arguments to display them in a nicely formatted message.
To ease the setting of errors, there is a macro #define setError() error.set (GetLastError(), __FILE__, __FUNCTION__, __LINE__); This way I'm able to use setError() at any time to respond to an error that an API function has set by adding it after I call that API function.
Unfortunately, this causes the code to look something like this:
SomeAPIFunction();
setError();
AnotherAPIFunction();
setError();
There is also a problem with constructors:
MyClass:MyClass()
: a (SomeAPIFunction), b (AnotherAPIFunction)
{
setError(); //what if both functions set an error?
}
As you can see, by using member initializer syntax, I'm actually limiting myself.
One way to fix this would be to wrap every API function:
int someAPIFunction()
{
int ret = SomeAPIFunction();
setError();
return ret;
}
The function portion of the error message would tell me which function originated the error. Of course, that has to be the worst possible way of dealing with this.
The solution, it seems, is to use variadic templates. The problem is, I have no idea what I'm supposed to be doing to get them working for this. I'd imagine the final code looks something like one of the following:
wrap<int, SomeAPIFunction (5)>();
wrap<int, SomeAPIFunction, 5>();
wrap<int, SomeAPIFunction> (5);
I've read things on beginning variadic templates, but they've all left me clueless of how to set up something like this. Could anyone point me in the right direction?
I found the following on a similar question:
#include <iostream>
template<void f(void)>
struct Wrap {
void operator()() const {
std::cout << "Pre call hook" << std::endl;
f();
}
};
namespace {
void test_func() {
std::cout << "Real function" << std::endl;
}
}
const Wrap<&test_func> wrapped_test_func = {};
int main() {
wrapped_test_func();
return 0;
}
The respondent noted that variadic templates would be a necessity to make this generic enough. It's a start, but I'm lost and grateful of any help on the matter.
I think you'll be able to make it work with this syntax:
wrap(&SomeAPIFunction, arg1, arg2);
The key is to let the compiler use type deduction to determine the template type parameters, since they get pretty messy in a hurry.
The code should look something like:
template<typename TRet, typename... TArgs>
TRet wrap( TRet(WINAPI *api)(TArgs...), TArgs... args )
{
return api(args...);
}
Naturally, you'll want to use a macro to hide the address-of-function operator, use stringizing to store the function name, and store the filename and line number also, passing all of that to the actual variadic function. You'll need variadic macros for that. In fact, could you do all of this just with variadic macros and no templates?