Say I have different functions, which have a variable number of arguments. The first argument is always a pointer obtained through other means. All other arguments I obtain through another template using template pack expansion.
Template that I use for calling these functions is as follows:
template<typename RT, typename... Args>
inline RT call(RT(*function)(Args...))
{
return function(pointer_from_somewhere, bind_argument<Args>::get_arg()...);
}
This obviously doesn't compile, as it performs template expansion for all arguments, thus there being too many arguments.
Since I always obtain the first argument through other means, how would I do template pack expansion for sizeof...(Args) - 1 arguments, starting from the 2nd argument?
EDIT:
While the template is slimmed down for demonstration purposes, it might be relevant, that the 1st argument (the pointer) is reinterpret_cast'ed always to the type of first argument. I use std::tuple_element<0, std::tuple<Args...>>::type for finding out the type of the 1st argument.
Is this what you are looking for?
template<typename RT, typename A0, typename... Args>
inline RT call(RT(*function)(A0, Args...))
{
return function(pointer_from_somewhere, bind_argument<Args>::get_arg()...);
}
Related
I would like to write a function that applies a function to each element of a parameter pack. The functions returns a std::tuple with the results of each invocation.
However, if the applied function returns void, I have to do something else, so I have a different overload for this case. But, almost all the ways I've found to expand the parameter pack do not work with void expressions, so I had to resort to what you see below, which seems a weird trick.
template<typename F, typename ...Args>
requires requires { std::tuple{std::declval<F>(Args)...}; }
auto for_each(F f, Args ...args) {
return std::tuple{f(args)...};
}
template<typename F, typename ...Args>
auto for_each(F f, Args ...args)
[[maybe_unused]] int a[] = {(f(Members), 0)...};
}
Note that I have to declare a unused variable and mark it with the attribute.
Which is the best way to obtain the expected result here?
This trick is the way to go pre-C++17, except that you need an extra , 0 in the array to support zero-length packs.
In C++17 and newer, use a fold expression: (f(args), ...);.
Note that you forgot perfect forwarding. You should be doing F &&f, Args &&... args, and then (f(std::forward<Args>(args)), ...);, and similarly for the first function.
I also question the value of having such a function. I'd understand doing this to a tuple, but if you already have a pack, you can do this manually at the call site.
I am wondering why the following code doesn't compile:
struct S
{
template <typename... T>
S(T..., int);
};
S c{0, 0};
This code fails to compile with both clang and GCC 4.8. Here is the error with clang:
test.cpp:7:3: error: no matching constructor for initialization of 'S'
S c{0, 0};
^~~~~~~
test.cpp:4:5: note: candidate constructor not viable: requires 1 argument, but 2 were provided
S(T..., int);
^
It seems to me that this should work, and T should be deduced to be a pack of length 1.
If the standards forbids doing things like this, does anyone know why?
Because when a function parameter pack is not the last parameter, then the template parameter pack cannot be deduced from it and it will be ignored by template argument deduction.
So the two arguments 0, 0 are compared against , int, yielding a mismatch.
Deduction rules like this need to cover many special cases (like what happens when two parameter packs appear next to each other). Since parameter packs are a new feature in C++11, the authors of the respective proposal drafted the rules conservatively.
Note that a trailing template parameter pack will be empty if it is not otherwise deduced. So when you call the constructor with one argument, things will work (notice the difference of template parameter pack and function parameter pack here. The former is trailing, the latter is not).
So, there should be a workaround. Something along these lines:
namespace v1 {
// Extract the last type in a parameter pack.
// 0, the empty pack has no last type (only called if 1 and 2+ don't match)
template<typename... Ts>
struct last_type {};
// 2+ in pack, recurse:
template<typename T0, typename T1, typename... Ts>
struct last_type<T0, T1, Ts...>:last_type<T1, Ts...>{};
// Length 1, last type is only type:
template<typename T0>
struct last_type<T0> {
typedef T0 type;
};
}
namespace v2 {
template<class T> struct tag_t{using type=T;};
template<class T> using type_t = typename T::type;
template<class...Ts>
using last = type_t< std::tuple_element_t< sizeof...(Ts)-1, std::tuple<tag_t<Ts>...> > >;
template<class...Ts>
struct last_type {
using type=last<Ts...>;
};
}
template<class...Ts>
using last_type=v2::late_type<Ts...>; // or v1
struct S
{
// We accept any number of arguments
// So long as the type of the last argument is an int
// probably needs some std::decay to work right (ie, to implicitly work out that
// the last argument is an int, and not a const int& or whatever)
template <typename... T, typename=typename std::enable_if<std::is_same<int, typename last_type<T...>::type>>::type>
S(T...);
};
where we check that the last type of a parameter pack is an int, or that we where only passed an int.
I am actually a little interested in the same thing (wanting to specialize templated parameter packs based on the final arguments).
I believe there may be a path forward by combining tuple reversal (std::make_tuple, back-port std::apply for C++14, etc):
How to reverse the order of arguments of a variadic template function?
Will get back on here if it is successful.
Related posts:
Parameters after parameter pack in function
Parameter with non-deduced type after parameter pack
EDIT:
Yup, figured it out after a bit; not perfect, as there are extra copies flying around, but it's a start.
If you know a simpler way than what I list below, please don't hesitate to post!
TL;DR
Can do stuff like this:
auto my_func_callable = [] (auto&& ... args) {
return my_func(std::forward<decltype(args)>(args)...);
};
auto my_func_reversed =
stdcustom::make_callable_reversed(my_func_callable);
And then implement this pseduo code:
template<typename ... Args>
void my_func(Args&& ... args, const my_special_types& x);
By doing something like:
template<typename... Args>
void my_func(Args&& ... args)
-> call my_func_reversed(args...)
template<typename... RevArgs>
void my_func_reversed(const my_special_types& x, RevArgs&&... revargs)
-> do separate things with revargs and my_special_types
-> sub_func_reversed(revargs...)
Using the above utilities.
Has some (a lot of) drawbacks. Will list them below.
Scope
This is for users of C++14 (maybe C++11), who want to borrow from the future (C++17).
Step 1: Reverse arguments
There are a few different ways to do this. I've listed out some alternatives in this example:
tuple.cc - Playground for two alternatives (credits in the source code):
Use foldable expressions and manipulate the index passed via std::apply_impl (credit: Orient).
Use recursive templates to construct a reversed index_sequence (credit: Xeo)
tuple.output.txt - Example output
This prints out the reversed_index_sequence template from Xeo's example. I needed this for debugging.
>>> name_trait<std::make_index_sequence<5>>::name()
std::index_sequence<0, 1, 2, 3, 4>
>>> name_trait<make_reversed_index_sequence<5>>::name()
std::index_sequence<4, 3, 2, 1, 0>
I chose Alternative 1, as it's easier for me to digest.
I then tried to formalize it right quick:
tuple_future.h - Borrowing from the future (namespace stdfuture), and making an extension (namespace stdcustom)
tuple_future_main.cc - Simple, advanced, and useful (see below) examples using the above
tuple_future_main.output.txt - Example output
Definition Snippets (adaptation of C++17 possible implementation of std::apply on cppreference.com):
namespace detail {
template <class F, class Tuple, std::size_t... I>
constexpr decltype(auto) apply_reversed_impl(F &&f,
Tuple &&t, std::index_sequence<I...>)
{
// #ref https://stackoverflow.com/a/31044718/7829525
// Credit: Orient
constexpr std::size_t back_index = sizeof...(I) - 1;
return f(std::get<back_index - I>(std::forward<Tuple>(t))...);
}
} // namespace detail
template <class F, class Tuple>
constexpr decltype(auto) apply_reversed(F &&f, Tuple &&t)
{
// Pass sequence by value to permit template inference
// to parse indices as parameter pack
return detail::apply_reversed_impl(
std::forward<F>(f), std::forward<Tuple>(t),
std::make_index_sequence<
std::tuple_size<std::decay_t<Tuple>>::value>{});
}
Usage Snippets: (from tuple_future_main.output.txt, copied from above)
auto my_func_callable = [] (auto&& ... args) {
return my_func(std::forward<decltype(args)>(args)...);
};
auto my_func_reversed =
stdcustom::make_callable_reversed(my_func_callable);
Step 2: Buckle your shoe (with reversed parameter packs)
First, establish the patterns for the final arguments that you wish to use. You will have to explicitly enumerate these, as you can only have one parameter pack.
(Taken from tuple_future_main.cc):
Example Scenario:
We like to add things to containers with a name, something of the form:
add_item(const Item& item, const string& name, Container& c)
We can also construct an Item with a [awfully large] number of overloads, and
we have convenenience overloads:
add_item(${ITEM_CTOR_ARGS}, const string& name, Container& c)
To do so, we can declare the following:
void add_item_direct(const Item& item, const string& name, Container& c)
Item create_item(Args&&... args)
And then define our generic interfaces:
template<typename... Args>
void add_item(Args&&... args) {
...
auto reversed = stdcustom::make_callable_reversed(callable);
reversed(std::forward<Args>(args)...);
}
template<typename ... RevArgs>
void add_item_reversed(Container& c, const string& name, RevArgs&&... revargs)
{
...
static auto ctor = VARIADIC_CALLABLE(create_item,);
...
auto item = ctor_reversed(std::forward<RevArgs>(revargs)...);
add_item_direct(item, name, c);
}
Now we can do stuff like: (taken from tuple_future_main.output.txt)
>>> (add_item(Item("attribute", 12), "bob", c));
>>> (add_item("attribute", 12, "bob", c));
>>> (add_item(Item(2, 2.5, "twelve"), "george", c));
>>> (add_item(2, 2.5, "twelve", "george", c));
>>> (add_item(Item(2, 15.), "again", c));
>>> (add_item(2, 15., "again", c));
>>> c
bob - ctor3: ctor3: ctor1: attribute (12, 10)
bob - ctor3: ctor1: attribute (12, 10)
george - ctor3: ctor3: ctor2: 2, 2.5 (twelve)
george - ctor3: ctor2: 2, 2.5 (twelve)
again - ctor3: ctor3: ctor2: 2, 15 ()
again - ctor3: ctor2: 2, 15 ()
Note the extra copy constructors... :(
Drawbacks
Ugly as hell
May not be useful
It could be easier to just refactor your interfaces
However, this could be used as a stop-gap to transition to a more generalized interface.
Possibly fewer lines to delete.
Especially if it plugs your development process with template explosions
Can't nail down where the extra copies are coming from.
It may be due to judicious usage of variadic lambdas
You have to carefully craft your base functionality
You shouldn't try to extend an existing function.
Parameter packs will be greedy in how they match to functions
You either need to explicitly spell out each overload you want, or bow down and let the variadic parameter pack dispatch to your desired functionality
If you find an elegant way around this, please let me know.
Template errors are shitty.
Granted, not too shitty. But it's hard to infer that you missed an available overload.
Wraps a lot of simple functionality in lambdas
You may be able to use make_reversed_index_sequence and directly dispatch to the function (mentioned in other SO posts). But that's painful to repeat.
Todo
Get rid of extra copies
Minimize the need for all the lambdas
Not necessary if you have a Callable
Try to combat parameter pack greediness
Is there a generalized std::enable_if matching that matches to both lvalue- and rvalue-references, and possibly handle forwarding compatible implicit copy constructors?
template<typename ... Args>
void my_func(Args&& ... args) // Greedy
void my_func(magical_ref_match<string>::type, ...)
// If this could somehow automatically snatch `const T&` and `T&&` from the parameter pack...
// And if it can be used flexible with multiple arguments, combinatorically
Hopes
Maybe C++17 will support non-final parameter pack arguments, such that all of this can be discarded... fingers crossed
From the working draft of the standard N3376 § 14.1 is a probable section to read about this.
Below is § 14.1.11
If a template-parameter of a class template or alias template has a
default template-argument, each subsequent template-parameter shall
either have a default template-argument supplied or be a template
parameter pack. If a template-parameter of a primary class template or
alias template is a template parameter pack, it shall be the last
template-parameter. A template parameter pack of a function template
shall not be followed by another template parameter unless that
template parameter can be deduced from the parameter-type-list of the
function template or has a default argument.
I'm following this great tutorial. The author heavily uses variadic templates and I came to a point where I'm stuck, can't understand. Can you help me?
1. Why isn't this compiling?
// this is simple
template<size_t I, typename T>
struct tuple_element
{
T value;
};
// this does NOT compiles: error: parameter pack 'Indices' must be at the end of the template parameter list
template <size_t... Indices, typename... Types>
struct tuple_impl : tuple_element<Indices, Types>...
{
};
Next, the author have this code that compiles fine:
template <size_t... Indices>
struct index_sequence
{
using type = index_sequence<Indices...>;
};
template <typename Sequence, typename... Types>
struct tuple_impl;
template <size_t... Indices, typename... Types>
struct tuple_impl<index_sequence<Indices...>, Types...>
: tuple_element<Indices, Types>...
{
};
2. Why in this case everything ok? I see almost the same pattern here: tuple_element<Indices, Types>...
3. Why this can't be compiled:
template <size_t... Indices>
void g(Indices...){}; //error: variable or field 'g' declared void
The error you are seeing is in the passing of parameters. This is a compile error:
template <size_t... Indices, typename... Types>
struct tuple_impl
{};
live example
The rule is you cannot have one pack followed by another in a template class template parameter list.
The second example is a specialization, where the pack rule does not exist. The template parameters of a specialization are merely the types and values which are extracted from the pattern matching against the primary templates, as guided by the <> portion of the specialization after the type name.
As they are never passed in in that same list & order, having one ... after another doesn't cause any ambiguity. With a primary template, the order matters, and anything after a ... is difficult to distinguish from more of the .... Probably to keep the compiler's job easier, even in cases where it cannot be ambiguous (say, a pack of literals followed by a pack of types), C++ bans its use.
The compiler would have no means to distinguish when the first sequence ends and the second starts - therefore it is allowed to have only one parameter pack in variadic templates, at the end.
tuple_impl<a, b, c, d, e, f> //is d still an index or already a type? what about e?
This works, because tuple_impl itself is a template that has itself only one parameter pack, the Types.... It just happes that in this specialization the first parameter is a template, too, which has a parameter pack, too. So, in contrast to one template with two packs, you have two templates with one pack each, which is ok.
This does not have to do with variadic templates, i.e. it would not work with a single argument either, for the same reason. The fact is, that since Indices... are not types but values, you are not defining a function. If it was not void, the compiler would have had problems later. Consider this example, which is slightly modified but essentially a similar construct:
template <size_t I>
unsigned g(I)
{}
The middle line is central: The compiler thinks that it is a variable definition, initialized with I. Therefore the error in your case, because variables of type void simply don't make sense. My compiler then emits a warning about the template, it thinks that g is a templated variable, and those are a C++1y extension. After that is done, he realizes the variable definition is not finished by a ;, emits an error and exits...
Just to add some important thing: this is a test snippet:
int main( int argc, char** argv )
{
using i3 = index_sequence<1, 2, 3>;
tuple_impl<i3, int, double, char> tup;
return 0;
}
Note: here you pass this i3 as the "index pack". The "master template" always defines how the parameters have to be passed to the template. The template<...> statement if set for specialization does not define anything, but just what internally the parameter combination may spread inside the specialization, but it's not a part of public interface.
For example, if you try to use <1, 2, 3, int, double, char> as a parameter specification (which would theoretically match the template parameter specification for the specialization), it will fail to compile.
I noted that much of boost and libc++/libstdc++ explicitly provide a default value of zero for SFINAE in code like
// libc++ http://llvm.org/svn/llvm-project/libcxx/trunk/include/memory
namespace __has_pointer_type_imp
{
template <class _Up> static __two __test(...);
template <class _Up> static char __test(typename _Up::pointer* = 0);
}
template <class _Tp>
struct __has_pointer_type
: public integral_constant<bool, sizeof(__has_pointer_type_imp::__test<_Tp>(0)) == 1>
{
};
However it confuses me as to why this would be expected when they explicitly make the call with 0. I remember hearing somewhere it was an optimization (to speed up the compiler when instantiating the template) but I don't fully understand how that would work. I looked at the standard and it has a section that briefly describes what happens with default-arguments in relation to template argument deduction.
14.8.2
At certain points in the template argument deduction process it is necessary to take a function type that makes use of template parameters and replace those template parameters with the corresponding template arguments. This is done at the beginning of template argument deduction when any explicitly specified template arguments are substituted into the function type, and again at the end of template argument deduction when any template arguments that were deduced or obtained from default arguments are substituted.
The last bit there sounds concerning to my question
and again at the end of template argument deduction when any template arguments that were deduced or obtained from default arguments are substituted.
However that sounds like the opposite of an optimization if it has to do more work. Does anyone have any reasoning why that 0 must be there, it works without it, but every single example of SFINAE in libc++ at least seems to explicitly put 0 there, even though they never call the function with no arguments.
You give a default value because you want to be able to not give that parameter, though the condition is still check !
Example:
template<typename T,
typename std::enable_if<
std::is_floating_point_v<T>
>::type = 0>
void foo() { std::cout << "1"; }
One can then call this function in the main with only one template parameter! Better, one does not even need to name the second parameter since it is unused.
A similar example when the parameter is given in the input of the function foo:
template<class T>
void foo(T t,
typename std::enable_if<
std::is_floating_point_v<T>
>::type = 0) { std::cout << "2"; }
then you could give a second parameter to the function foobut you do not want to do that in general.
This question is a follow-up of How to deduce the type of the functor's return value?
I'm reformulating it in a more abstract way.
Given the pseudocode of a template function
template <typename Arg, typename Fn>
auto ComputeSomething(Arg arg, Fn fn) -> decltype(<decl-expr>)
{
// do something
// ............
return fn(<ret-expr>)
}
where <ret-expr> is an arbitrary expression which involves arg, what shall I use for <decl-expr> to set the return type of ComputeSomething equal to the return type of the functor.
The functor may be a class, a lambda or a function pointer.
Partial solutions I found so far.
(a) The answer for my linked question done by ecatmur. Essentially, it is repeating the return statement in <decl-expr>. Problems: it is error-prone and wouldn't work if contains local variables.
(b) It works only for function pointers
template <typename Arg, typename Ret>
Ret ComputeSomething(Arg arg, Ret(*fn)(Arg))
(c) It assumes that the argument of the functor is of type Arg (which may not hold in general) and requires Arg to be default-constructible
template <typename Arg, typename Fn>
auto ComputeSomething(Arg arg, Fn fn) -> decltype(fn(Arg())
(d) Using std::declval which is supposed to lift the default-constructible restriction, as suggested in how to deduce the return type of a function in template. Could anybody explain how it works?
template <typename Arg, typename Fn>
auto ComputeSomething(Arg arg, Fn fn) -> decltype(fn(std::declval<Arg>())
Use result_of. It is backwards compatible and takes all the ugly declval pain out of your code. You still need to remember to add rvalue reference qualifiers (&&) if you actually just forward values.
Something else I find important: Your function forwards arguments to another function. In such cases you should always use rvalue references to pass the arguments.
If all you are trying to do is improve maintainability: there are several attempts at a RETURNS macro around that try to minimize the repetition between the return type declaration and the actual return expression, but I haven't seen any that allows a function body that contains more than the actual return statement.
As for how declval works: Its compiler dependent. It isn't allowed to occur in an evaluated content and its argument can be an incomplete type. See 20.2.4
std::declval is a function template that is only declared (not defined). It can thus only be used in unevaluated contexts such as the argument to sizeof and decltype. It is declared to return an rvalue of the specified type. This allows you to use it to manufacture a dummy parameter for a function call in a decltype expression.
e.g.
typedef decltype(fn(std::declval<Arg>())) t;
declares t to be the type of the result of calling fn with an rvalue of type Arg. This is similar to your case (c) (fn(Arg())), but it doesn't require anything of Arg, so it works on types without default constructors.
If your return expression uses a local variable of type foo, then you can use decltype(fn(std::declval<foo>())), again regardless of how you construct a foo.
If you need an lvalue, such as a named object or an lvalue reference, then you can use std::declval<foo&>(). This allows you to handle the case where the type depends on whether you have an lvalue or an rvalue.
Here's my own solution, the best I could get
template <typename Arg, typename Fn>
typename std::result_of<Fn(Arg)>::type ComputeSomething(Arg arg, Fn fn)
To make (c) works for anything, you need 2 overloads. 1st as shown in (c), 2nd:
template <typename Arg, typename Ret>
Ret ComputeSomething(Arg arg, std::function<Ret(Arg)> fn)
Also, as gcc bug 54111 shows - deduction of return type is very unreliable.
A variant of (b) working not only with function pointers should be something like
template<typename Arg, typename Ret>
Ret ComputeSomething (Arg arg, function<auto (Arg) -> Ret> f)