I'm trying to create a way to directly expand multiple parameter packs. I have created a function template<size_t X,typename F> auto sequenceFunc(F&& f), that calls a given function f with a expanded integer_sequence.
This works well for small functions like this:
template<typename T,
size_t A,size_t B>
vec<B,T> col(const mat<A,B,T>& a,const size_t& i){
return sequenceFunc<A>([&](auto... J) -> vec<B,T>{
return { a[J][i]... }; //expands to a[0][i], a[1][i], ... a[A-1][i]
});
}
Unfortunately I can't expand multiple parameter packs, even if I follow the rule, that only one parameter pack can be inside a ...-expression.
This is my attempt at using this function for matrix multiplication:
template<typename S,typename T,
size_t A,size_t B,size_t C>
mat<C,B,S> mul(const mat<A,B,S>& a,const mat<C,A,T>& b){
return sequenceFunc<B>([&](auto... I)->mat<C,B,S>{ //for all B rows in a...
return {
sequenceFunc<C>([&](auto... J)->vec<C,S>{ // ... look at all C columns in b and calculate dot product.
auto i = I; //putting "I" outside the expansion of "J"
return {
dot(row(a,i),col(b,J))... //expands J
};
})... //expands I
};
});
}
This is the error:
error: parameter packs not expanded with '...':
auto i = I;
^
I don't really understand why an expansion is necessary, because there is another ... outside the expression. I use GCC 5.1.0.
Information vec and mat are only using-declarations for std::array and a nested std::array<std::array<A,T>,B>
This is gcc bug 47226. It's still open, and the code example still fails on gcc 5.2.0, while it compiles just fine on clang 3.6. Your code looks correct to me.
I just encountered the same problem. Didnt find a better dupe and didnt want to open a new question, but still want to share my findings. In a comment to a similar question I found a workaround that puts the parameters in a tuple and then unpacks it inside the lambda (sorry dont find the link anymore). However, that solution requires C++17 (std::apply and more).
My case was something like this:
struct Foo{
template <typename T,typename ...ARGS>
void foo(T t,ARGS...args){
auto x = [&](){ t(args...);}
}
};
which is not working with gcc 4.8.5. To my surprise, simply explicitly writing out the lambda as functor works like a charm:
template <typename T,typename ...ARGS>
struct FooFunct{
void operator()(T t,ARGS...args){
t(args...);
}
};
struct Foo{
template <typename T,typename ...ARGS>
void foo(T t,ARGS...args){
auto x = FooFunct<T,ARGS...>();
}
};
I find it a bit strange, that gcc swallows this, while not the first one. Afaik lambdas are just syntactic sugar for anonymous functors on function scope. Probably my knowledge on compilers is just too little to understand what is the problem in fixing this bug.
Related
Consider the following example:
template<auto const fnc>
struct dummy_s {
typedef std::invoke_result<decltype(fnc), std::uint8_t >::type return_t;
};
int main() {
dummy_s<[](std::uint8_t const& n) -> bool { return true ^ n; }>::return_t s = true;
}
Is there anyway to get the return type without specifying std::uint8_t or whatever the number of arguments is, as template parameter as example.
You could write a metafunction that gives you the type of the first argument
template<typename Ret, typename Arg>
auto arg(Ret(*)(Arg)) -> Arg;
and then decay the lambda fnc to a function pointer (using + say), that you pass to arg, and then use that in the typedef.
typedef std::invoke_result<decltype(fnc),
decltype(arg(+fnc))>::type return_t;
This will only work for lambdas that don't capture anything, and that take a single argument.
You can also considerably simplify the typedef inside the struct by simply using arg directly like this
using return_t = decltype(arg(+fnc)); // using is cleaner than a typedef as well
This avoids using invoke_result entirely, and lets you define arg in a way that allows lambdas with multiple arguments to be passed to it
template<typename Ret, typename Arg, typename ...R>
auto arg(Ret(*)(Arg, R...)) -> Arg;
Here's a demo
As I said in my comment, each time I though I needed this feature I realized later I was going the wrong path. The reason is that as soon as the lambda is a template (auto) there is no hope to make it work.
More generally, if you don't have clue of the "universe" inputs of a function you don't really have a function, conceptually speaking.
If you think you still need it, you can use Boost.TypeTraits, lambda decay and function pointers.
#include<cstdint>
#include<boost/type_traits.hpp>
int main(){
auto f = [](std::uint8_t const& n) -> bool {return true ^ n;};
using f_return = boost::function_traits<decltype(*+f)>::result_type;
static_assert( std::is_same<f_return, bool>{} , "!");
}
With any generalization of f, overload or templates, will not work.
You are really lucky that this sort of works because of a series of quirks in the language starting from the existence of monomorphic functions (inherited from C, pointer decay, etc). Conceptually, it is horrible.
Having said that, there is also a potential problem that is very sensitive to the version of C++ you are using, that is the use of lambdas in template (non-evaluated) contexts.
This is working solution based on your code.
It really works as is with certain combinations of compilers and flags, for example https://godbolt.org/z/5x684nfWc :
#include<cstdint>
#include<boost/type_traits.hpp>
template<auto fnc>
struct dummy_s {
using return_t = typename boost::function_traits<decltype(*+fnc)>::result_type;
};
int main() {
typename dummy_s<[](std::uint8_t const& n) -> bool { return true ^ n; }>::return_t s = true;
}
The code below doesn't compile (see error below the code). Can you please explain why?
template <class F, class... Arg>
void for_each_argument(F f, Arg&&... arg)
{
f(std::forward<Arg>(arg...));
}
int main()
{
for_each_argument(
[](const auto& a){std::cout<< a;}, "Aa", 3, 4);
return 0;
}
Here is an error message:
7:4: error: expression contains unexpanded parameter pack
'Arg'
f(std::forward(arg...));
You have several issues in your code. First of, your original line
f(std::forward<Arg>(arg...));
Is not correct syntax at all - you are expanding arg without properly expanding Arg in template. Now, you can fix at least that by
f(std::forward<Arg>(arg)...);
This would be better, but still wrong - you will call your lambda once with 3 arguments, while it only accepts one - and instead, you want to call lambda 3 times with a single argument.
There are several ways to do this. First, and the least preferred, is to call the function recursively, as other answer suggests. This prompts ugly syntax, and also adds burden on compiler for recursive template instantiation. Much better solution is to expand the argument using array trick, for example (ignoring the forward for simplicity):
auto lam = [&f](const auto& a) { f(a); return true;}
bool arr[] = { lam(std::forward<ARG>(arg))... };
(void)arr;
In C++ 17 you can use fold expression to achieve even more neat syntax:
(f(std::forward<ARG>(arg)), ...);
Expanding a parameter pack works in contexts that expect a comma separated list.
That is, your code:
f(std::forward<Arg>(arg...));
It attempting to expand into:
f( "Aa", 3, 4 );
And the lambda you have supplied does not support such a call.
To expand a parameter pack into multiple function calls, use a recursive function.
template <class F>
void for_each_argument(F f)
{
// (No args)
}
template <class F, class FirstArg, class... MoreArgs>
void for_each_argument(F f, FirstArg&& first_arg, MoreArgs&&... more_args)
{
f( std::forward<FirstArg>(first_arg) );
for_each_argument( f, std::forward<MoreArgs>(more_args)... );
}
While compiling the following (reduced) code:
#include <tuple>
#include <stdlib.h>
template<size_t N> struct tying;
template<> struct tying<1> {static auto function(auto& o) -> decltype(auto) {auto& [p1] = o;return std::tie(p1);}};
template<> struct tying<2> {static auto function(auto& o) -> decltype(auto) {auto& [p1,p2] = o;return std::tie(p1,p2);}};
template<typename T, size_t N> concept bool n_components =
requires(T& object) {
{ tying<N>::function(object) };
};
typedef struct
{
int a;
float b;
} test_t;
int main(int argc, char* argv[])
{
constexpr size_t n = 1;
constexpr bool t = n_components<test_t, n>;
printf("n_components<test_t, %d>: %s\n", n, t ? "yes" : "nope");
return 0;
}
with gcc specific options -std=c++1z -fconcepts the gcc (version 7.3.0, and x86-64 gcc-trunk at godbolt also) fails with an error:
error: only 1 name provided for structured bindingnote: while 'test_t' decomposes into 2 elements
I was very surprised by this, as the error "raises" inside the requires-expression, and to my understanding, this should result in n_components constraint to get evaluated to false, as the requirement is not satisfied.
Note: replacing constexpr size_t n = 1; with other values "fixes" the error, so I presume the n_components constraint is not to blame:
replacing with n = 2 the n_components constraint evaluates to "true" as expected.
replacing with n = 3 the n_components constraint evaluates to "false" as expected - due to referring to unspecialized tying<3> struct.
It seems there are no other compilers supporting the c++ concepts and structured bindings available yet to compare with.
PS. I was playing around with "poor man's reflection" a.k.a. magic_get and hoped to replace the unreliable is_braces_constructible trait with something more robust...
Here's a partial solution for clang since 5.0.
It is distilled from a recent reddit post
Find the number of structured bindings for any struct
The method is non-standard, using gnu extension statement expressions to effectively SFINAE on structured binding declarations. It is also non-portable as gcc fails to parse structured binding in statement expression in a lambda trailing return type.
template <typename... Ts> struct overloads : Ts... { using Ts::operator()...; };
template <typename... Ts> overloads(Ts...) -> overloads<Ts...>;
template <typename T>
auto num_bindings_impl() noexcept {
return overloads{
[](auto&& u, int) -> decltype(({auto&& [x0] = u; char{};}))(*)[1] {return {};},
[](auto&& u, int) -> decltype(({auto&& [x0,x1] = u; char{};}))(*)[2] {return {};},
[](auto&& u, int) -> decltype(({auto&& [x0,x1,x2] = u; char{};}))(*)[3] {return {};},
[](auto&& u, int) -> decltype(({auto&& [x0,x1,x2,x3] = u; char{};}))(*)[4] {return {};},
[](auto&& u, unsigned) -> void {}
}(declval<T>(), int{});
};
This implementation to be used only in unevaluated context and expanding out
for as many bindings as you wish, up to compiler implementation limits.
Then, you can define traits that work up to that limit:
template <typename T>
inline constexpr bool has_bindings = [] {
if constexpr ( ! is_empty_v<T> )
return ! is_void_v< decltype(num_bindings_impl<T>()) >;
else return false;
}();
template <typename T>
inline constexpr unsigned num_members = [] {
if constexpr ( ! is_empty_v<T> )
return sizeof *num_bindings_impl<T>();
else return 0;
}();
https://godbolt.org/z/EVnbqj
The immediate situation
I was very surprised by this, as the error "raises" inside the requires-expression
To be precise, the error happens in the body of the functions you wrote. We can boil down your code to:
void function(auto& arg);
void function_with_body(auto& arg)
{
arg.inexistent_member;
}
template<typename Arg>
concept bool test = requires(Arg arg) { function(arg); };
// never fires
static_assert( test<int> );
template<typename Arg>
concept bool test_with_body = requires(Arg arg) { function_with_body(arg); };
// never fires
static_assert( test_with_body<int> );
(on Coliru)
As far as the requires expression are concerned, the function calls are valid C++ expressions: there's nothing tricky about their return and parameter types, and the supplied argument can be passed just fine. No check is performed for the function bodies, and with good reason: the function or function template may have been declared but not defined yet (i.e. as is the case for function). Instead, it's normally up to the function template writer to make sure that the function body will be error-free for all (sensible) specializations.
Your code uses return type deduction, but that won't make too much of a difference: you can declare a function with a placeholder type (e.g. decltype(auto)) without defining it, too. (Although a call to such a function is in fact an invalid expression since the type cannot be deduced and that's visible to a requires expression, but that's not what you're doing.) In pre-concepts parlance, return type deduction is not SFINAE-friendly.
Structured bindings
As to your wider problem of writing a constraints around structured bindings, you are out of luck. As best as I know these are all the obstacles:
There is no interface for querying the decomposition size of a type, even though the implementation blatantly has access to the information in order to type-check structured binding declarations. (std::tuple_size is for tuple-like types only.). This could be worked around by blindingly trying sizes in increasing order though.
You can only ever write constraints around types and expressions, but structured bindings can only appear in normal variable declarations. (If function parameters could be structured bindings we could work around that.) No trickery with lambda expressions allowed because these can't appear in an unevaluated operand, such as in the body of a requires expression.
The closest you can go is emulate what the language is doing during an actual structured binding. That can get you support for tuple-like types (including arrays), but not 'dumb' aggregates.
(range-for is another case of a statement-level constraint that you can't fit into an expression constraint, and where emulating the language can only get you so far.)
While trying to reply to this question, I found my self in the need of creating a bunch of parameters for a variadic function on the fly where:
the number of the parameters is not given
the types are all the same, but unknown (even if they must be default constructible)
At runtime, the standard containers and a for loop can be used to do that.
Anyway, I'd like to generate a set of parameters at compile time, so as to be able to forward them to a variadic function.
Because of that, a std::tuple seemed the obvious solution.
Here arose the question: given a size N and a default constructible type T at compile time, how can I write a function to generate a tuple of the given size?
I'm looking for something like this:
auto tup = gen<MyType, N>();
On SO is a notable example of a recursive generator based structs but I was struggling with a function based solution and I've not been able to find it anywhere.
A correctly written forwarding function (a la std::apply) should work with std::array<T, N> and anything else that implements the std::tuple_size/std::get interface. That said,
template<size_t, class T>
using T_ = T;
template<class T, size_t... Is>
auto gen(std::index_sequence<Is...>) { return std::tuple<T_<Is, T>...>{}; }
template<class T, size_t N>
auto gen() { return gen<T>(std::make_index_sequence<N>{}); }
Here is a possible implementation of such a function:
#include<utility>
#include<tuple>
template<typename T>
constexpr auto
params(std::index_sequence<0>) {
return std::tuple<T>{};
}
template<typename T, std::size_t I, std::size_t... O>
constexpr auto
params(std::index_sequence<I, O...>) {
auto tup = std::tuple<T>{ T{} };
auto seq = std::make_index_sequence<sizeof...(O)>{};
return std::tuple_cat(tup, params<T>(seq));
}
template<typename T, std::size_t N>
constexpr auto
gen(std::integral_constant<std::size_t, N>) {
return params<T>(std::make_index_sequence<N>{});
}
int main() {
auto tup = gen<int>(std::integral_constant<std::size_t, 3>{});
static_assert(std::tuple_size<decltype(tup)>::value == 3, "!");
}
For the sake of simplicity, I've used int as a type.
With a small effort, user defined types can be used and the constraint of having them default constructible can be relaxed.
someone already asked this question, but the thread ended up with the original question not getting answered.
suppose you have this:
template<size_t i, class f_type>
void call_with_i(f_type f);
functor_type is either:
a) a struct with a method that has the following signature:
template<size_t i> operator()() const;
or, b) a function that looks like this:
template<size_t i> foo();
I want "call_with_i<42>(foo)" to be equivalent to "foo<42>()", but I can't figure out the right syntax to make that happen. I'd be satified with a solution that does just (a) but (a)+(b) would be great. I've already tried these syntaxes:
f< i >(); // doesn't work
f()< i >; // doesn't work
f.operator< i >(); // doesn't work
f.operator()< i >; // doesn't work
f.operator()< i >(); // works on msvc, but doesn't work on gcc.
How do you invoke operator() with explicit template arguments? Is there a way to invoke it in a way that the same syntax would also call a templated free function?
p.s. If you're wondering what i'm using this for, its because I'm writing a function repeat_to where repeat_to<10>(f) invokes f(0) then f(1) ... f(10). I'm using this to iterate through multiple boost::fusion vectors in parallel by index. yeah, i could use iterators, or i could just use a named member function, but i still want to know the answer.
edit note: i striked out stuff because passing a templated free function as an arg doesn't make any sense.
The member template is a dependent name, because its semantics depend on the type of f_type. That means you should put "template" before its name (to disambiguate the use of the "less-than" token), similar to how you should put typename before dependent qualified names:
template<size_t i, class f_type>
void call_with_i(f_type f) {
f.template operator()<i>();
// f.template foo<i>();
}
As a workaround, you may use a helper type:
template<size_t N> struct size_t_ { }; // or boost::mpl::int_
template<size_t i, class f_type>
void call_with_i(f_type f) {
f(size_t_<i>());
}
Now, you could define your operator() as follows:
template<size_t i> void operator()(size_t_<i>) const {
// i was deduced automatically by the function argument.
}
This comes handy for templated constructors, for which you cannot do f_type()<i>() or something. They will have to be deducible in that case.
In a case like yours I would use boost::function as functor type. You can then pass both function objects and function pointers while retaining the same interface.
#include <iostream>
template<size_t i, class f_type> void call_with_i(f_type f);
struct A {
template < size_t i >
void operator()() const {
/* no link err in demo */
}
template < size_t i >
void foo() {
/* no link err in demo */
}
};
int main(int argc, char * const argv[]) {
A f;
enum { Constant = 42 };
f.operator()<Constant>();
f.foo<Constant>();
return 0;
}
Is there a way to invoke it in a way that the same syntax would also call a templated free function?
Can you clarify? (pseudocode, or something)