Is it possible to expand a parameter pack with a lambda function? - c++

I think my question is a corner case, of how far you can go with parameter pack expansion and it's a little hard to explain, what I want. The idea is easiest to express with a little code, so lets have a look at the following lines:
// <main.cpp>
#include <tuple>
#include <iostream>
// this function is supposed to return a std::tuple of function objects
// for each template argument type, there should be one such function object,
// that takes a value of this type and returns its half.
template <class... arg_t>
auto make_divide_by_two_lambda_tuple() {
return std::make_tuple(
[](const arg_t& elem) -> arg_t
{
return elem/2;
}...
);
}
int main()
{
// lets initialise a tuple with our function
auto value = make_divide_by_two_lambda_tuple<int, float>();
/*
* If everything workes as planned, the tuple has this structure
* value<0> := [](const int&){ ... }
* value<1> := [](const float&){ ... }
*/
// and we are able to use our functions in the expected way
std::cout << "5/2 (int version) = " << std::get<0>(value)(5) << std::endl;
std::cout << "5/2 (float version) = " << std::get<1>(value)(5) << std::endl;
return 0;
}
For clang(4.0.1), this example compiles and run as I expect it to do:
$ clang++ -std=c++14 ../main.cpp
$ ./a.out
5/2 (int version) = 2
5/2 (float version) = 2.5
For g++(7.1.1), this example does fail to compile:
$ g++ -std=c++14 ../main.cpp
../main.cpp: In function ‘auto make_divide_by_two_lambda_tuple()’:
../main.cpp:7:28: error: parameter packs not expanded with ‘...’:
[](const arg_t& elem) -> arg_t
^~~~~
../main.cpp:7:28: note: ‘arg_t’
../main.cpp:7:28: error: parameter packs not expanded with ‘...’:
../main.cpp:7:28: note: ‘arg_t’
../main.cpp:10:4: error: expansion pattern ‘<lambda>’ contains no argument packs
}...
^~~
../main.cpp: In function ‘int main()’:
../main.cpp:15:10: error: ‘void value’ has incomplete type
auto value = make_divide_by_two_lambda_tuple<int, float>();
So it seems, that gcc is willing to use a parameter pack inside the argument list of a lambda expression. But using the whole lambda is stretching it too far for gcc to accept.
Is this use of lambda expressions undefined behaviour, or is one compiler (hopefully gcc) wrong?
PS.: I also checked the docs, but it only explains, where you can use parameter pack expansion, and not what statments you can expand.

Related

Standard overloaded std::abs doesn't match std::function<double (double)>

I'm getting the following error
min.cpp:17:30: error: no viable conversion from '<overloaded function type>' to 'Container::UnaryFun' (aka 'function<double (double)>')
this->addFunction("abs", abs);
when trying to compile the following code:
#include <cmath>
#include <string>
#include <functional>
class Test
{
public:
using UnaryFun = std::function<double (double)>;
Test()
{
this->addFunction("abs", abs);
}
auto addFunction(const std::string& name, UnaryFun fun) -> void
{
// ...
}
};
auto main() -> int {
Test eval;
return 0;
}
I've tried to check the declaration of std::abs for argument double and return type double and looks like this:
inline _LIBCPP_INLINE_VISIBILITY double abs(double __lcpp_x) _NOEXCEPT {
return __builtin_fabs(__lcpp_x);
}
in /usr/local/Cellar/llvm/15.0.7_1/include/c++/v1/stdlib.h.
It is accesible specifically for the double type. I've checked this by adding:
double a = 5;
double b = std::abs(a);
and this compiles without problems or conversion warnings.
I've tried to declare my own abs function like so:
inline double xabs(double val)
{
return val < 0 ? -val : val;
}
and then change the following code like so to use this new xabs instead of std::abs
this->addFunction("abs", xabs);
and after this change, the code compiles.
Any ideas why the code with std::abs doesn't compile?
My environment:
OS: Mac OS 12.6
Compiler:
Apple clang version 14.0.0 (clang-1400.0.29.202)
Target: x86_64-apple-darwin21.6.0
Thread model: posix
InstalledDir: /Applications/Xcode.app/Contents/Developer/Toolchains/XcodeDefault.xctoolchain/usr/bin
Command to compile: g++ -std=c++2a -o min min.cpp
Update based on comments
I dug a bit deeper, and it seems that there is a problem with how std::function is declared, which led to the problem above.
If I declare addFunction like so, without std::function, the problem disappears.
auto addFunction(const std::string& name, double (*fun)(double)) -> void
{
}
This means that the compiler cannot figure out the matching abs if std::function is used but it can identify the matching overload if the type of the function is described directly without std::function.
The problem is that, since it has multiple overloads, std::abs doesn't have a single type. That means that the compiler can't select a std::function constructor to use to convert it since it can't deduce a type for the constructor's template parameter.
There are a couple of ways to get around that:
Use a cast:
addFunction("abs", std::static_cast<double(*)(double)>(std::abs));
Wrap it in a lambda:
addFunction("abs", [](double d) { return std::abs(d); });
As you've done, wrap it in a non-overloaded function

std::function::target with template parameter pack gives "error: expected primary-expression" [duplicate]

This question already has answers here:
Where and why do I have to put the "template" and "typename" keywords?
(8 answers)
Closed 2 years ago.
When I attempt to call the method target on a std::function object using a template parameter pack, the compiler throws an error, but it works fine if the template parameters are specified explicitly in a proxy variable.
Example, modified from cppreference.com:
#include <functional>
#include <iostream>
int f(int, int) { return 1; }
int g(int, int) { return 2; }
template <typename... Args>
void test(std::function<int(Args...)> const& arg)
{
auto && ptr = arg.target<int(*)(Args...)>(); // error: expected primary-expression before 'int'
if (ptr && *ptr == f)
std::cout << "it is the function f\n";
if (ptr && *ptr == g)
std::cout << "it is the function g\n";
}
int test()
{
test<int, int>(std::function<int(int, int)>(f));
test<int, int>(std::function<int(int, int)>(g));
}
I've tried various other ways to call target including the following:
int (*const* ptr)(Args...) = arg.target<int(*)(Args...)>(); // error: expected primary-expression before 'int'
int (*const* ptr)(int, int) = arg.target<int(*)(Args...)>(); // error: expected primary-expression before 'int'
int (*const* ptr)(int, int) = arg.target<int(*)(int, int)>(); // error: expected primary-expression before 'int'
const std::function<int(Args...)>& func = arg;
auto && ptr = arg.target<int(*)(Args...)>(); // error: expected primary-expression before 'int'
The compiler only appeared to be satisfied when using a proxy variable as seen here:
const std::function<int(int, int)>& func = arg;
auto && ptr = func.target<int(*)(Args...)>(); // OK, but requires specifying the template arguments for func
As can be seen, this workaround deviates from the previous non-working example only by explicitly specifying the function parameters instead of relying on the parameter pack. (I could bypass the proxy variable with a static_cast e.g. static_cast<std::function<int(int,int)>&>(arg).target<int(*)(Args...)>(), but this also requires knowing the parameters for the cast.) If I already knew what parameters were going to be used then I wouldn't be using a variadic template since it wouldn't be necessary. But since I don't, how can I fix this? Am I doing something wrong, is this a compiler bug, or what exactly is going on here?
Note:
For reference, I'm compiling with GCC version 6.3.0 with MinGW on Windows 10.
arg.template target<int(*)(Args...)>(
You need to disambiguate when the std function type is dependent on template args.
C++ doesn't know arg.target is a template when parsing your template function prior to the function being called. And it has to parse it before it is called; this isn't a macro.
So whenever you name a type in a context dependent on your template arguments, or instantiate a template in a context dependent on your template args, you have to tell the parser.

Mismatched deduction of auto types between different c++ compilers

So, I am trying to implement the dot product (https://en.wikipedia.org/wiki/Dot_product) in some flavour of modern C++ and came up with the following code:
#include <iostream>
template<class... Args>
auto dot(Args... args)
{
auto a = [args...](Args...)
{
return [=](auto... brgs)
{
static_assert(sizeof...(args) == sizeof...(brgs));
auto v1 = {args...}, i1 = v1.begin();
auto v2 = {brgs...}, i2 = v2.begin();
typename std::common_type<Args...>::type s = 0;
while( i1 != v1.end() && i2!= v2.end())
{
s += *i1++ * *i2++;
}
return s;
};
};
return a(std::forward<Args>(args)...);
}
int main()
{
auto a = dot(1,3,-5)(4,-2,-1);
std::cout << a << std::endl;
}
Online: https://gcc.godbolt.org/z/kDSney and also: cppinsights
The code above compiles and executes nicely with g++, however clang (and icc and msvc) choke on it:
clang++ ./funcpp.cpp --std=c++17
./funcpp.cpp:12:4: error: 'auto' deduced as 'std::initializer_list<int>' in declaration of
'v1' and deduced as 'const int *' in declaration of 'i1'
auto v1 = {args...}, i1 = v1.begin();
^ ~~~~~~~~~ ~~~~~~~~~~
./funcpp.cpp:28:11: note: in instantiation of function template specialization
'dot<int, int, int>' requested here
auto a = dot(1,3,-5)(4,-2,-1);
^
1 error generated.
Now, if I break up the definition of v1, v2, i1, i2 like:
auto v1 = {args...} ;
auto i1 = v1.begin();
auto v2 = {brgs...};
auto i2 = v2.begin();
clang and msvc have no problems, icc still chokes:
<source>(10): error: static assertion failed
static_assert(sizeof...(args) == sizeof...(brgs));
^
detected during instantiation of "auto dot(Args...) [with Args=<int, int, int>]" at line 30
compilation aborted for <source> (code 2)
Execution build compiler returned: 2
However if I remove the offending static_assert then icc has no issues compiling the code either.
And beside of the (typical) question: which is right and why :) the concrete question is:
According to [dcl.spec.auto] :
if the type that replaces the placeholder type is not the same in each deduction, the program is ill-formed
clang correctly identified that there are two different types defined in the line in question: 'auto' deduced as 'std::initializer_list<int>' in declaration of 'v1' and deduced as 'const int *' in declaration of 'i1' so I'd like to hear your opinions whether:
did I hit some undocumented g++ extension considering this specific situation (not mentioned in https://gcc.gnu.org/onlinedocs/gcc-9.2.0/gcc/C_002b_002b-Extensions.html#C_002b_002b-Extensions) since g++ to my knowledge correctly handles the different types in an auto declaration list,
or by any chance g++ did not deduce the two types to be different (... hm...)
or something else?
Thanks for reading through this long question.
(As a bonus if someone could answer why icc fails on the static_assert would be great.)
Expanding from my comments:
g++ does not do this always, consider the example auto i = 0l, f = 0.0;, it gives the error:
test.cpp: In function ‘int main()’:
test.cpp:4:5: error: inconsistent deduction for ‘auto’: ‘long int’ and then ‘double’
4 | auto i = 0l, f = 0.0;
If we compile your program and print the types of the variables (with this method), we get the following output:
v1: std::initializer_list<int>, i1: int const*
v2: std::initializer_list<int>, i2: int const*
using gcc version 9.2.0, with flags -std=c++17 -pedantic -Wall -Wextra without any warning or error.
By your comment of the standard this program is ill-formed and the standard specifies that there should be emitted a diagnostic message (warning or error) unless otherwise specified (which it is not, in this case). Hence I would say that this is a bug in gcc.
It is a known bug.
The static_assert fail on ICC is definitely a bug. I found a simple workaround by moving static_assert into a separate function. Not very elegant solution, but it works.
With slight modifications, this is the code that compiles with GCC, Clang and ICC:
template<std::size_t size, class... Args>
void args_no_guard(Args... args)
{
static_assert(sizeof...(args) == size);
}
template<class... Args>
auto dot(Args... args)
{
return [=](auto... brgs)
{
constexpr auto n = sizeof...(args);
args_no_guard<n>(brgs...);
using T = std::common_type_t<decltype(args)..., decltype(brgs)...>;
const T v1[]{static_cast<T>(args)...};
const T v2[]{static_cast<T>(brgs)...};
T dot = 0;
for (std::size_t i = 0; i < n; ++i)
dot += v1[i] * v2[i];
return dot;
};
}

Passing a function object to a constructor [duplicate]

This question already has an answer here:
Pass anonymous function object to std::function?
(1 answer)
Closed 7 years ago.
What I am trying to achieve is to make a functor that can take different functors as arguments.
Edit: the reason for my problem, the "most vexing parse", and the solution are well-described: see this question and answer, the whole most-vexing-parse tag, and even the wikipedia page. Still, I was not able to identify the problem before asking, and will leave this question as it might help others.
What I did:
In a header file functor.hpp:
#ifndef FUNCTOR_HPP
#define FUNCTOR_HPP
#include <functional>
template <typename T, typename BinOp = typename std::plus<T>>
struct doer {
BinOp op;
doer(BinOp o = std::plus<T>()) : op(o) {}
T operator()(const T& a, const T& b) const
{ return op(a, b); }
};
#endif // FUNCTOR_HPP
With this header, I can write a program functor.cpp like this:
#include <iostream>
#include "functor.hpp"
int main()
{
doer<int> f;
std::cout << f(3, 7) << std::endl;
}
and I can compile and run it to get, as expected:
$ make functor
g++ -std=c++14 -pedantic -Wall functor.cpp -o functor
$ ./functor
10
$
I am struggling to find a way to instantiate my doer with a different operator (not std::plus<T>).
doer<int, std::multiplies<int>> f2(std::multiplies<int>());
This compiles without a problem, but I have not been able to figure out a way to call f2(3, 7), to get the product 21. For example, if I add another line to the program:
int r = f2(3, 7);
and try to compile, I get:
$ make functor
g++ -std=c++14 -pedantic -Wall functor.cpp -o functor
functor.cpp: In function ‘int main()’:
functor.cpp:10:20: error: invalid conversion from ‘int’ to ‘std::multiplies<int> (*)()’ [-fpermissive]
int r = f2(3, 7);
^
functor.cpp:10:20: error: too many arguments to function ‘doer<int, std::multiplies<int> > f2(std::multiplies<int> (*)())’
functor.cpp:9:37: note: declared here
doer<int, std::multiplies<int>> f2(std::multiplies<int>());
^
functor.cpp:10:20: error: cannot convert ‘doer<int, std::multiplies<int> >’ to ‘int’ in initialization
int r = f2(3, 7);
^
What is going on? Seems almost like f2(3, 7) somehow is not calling the overloaded operator()...
Most vexing parse. Try this:
doer<int, std::multiplies<int>> f2((std::multiplies<int>()));
or this:
doer<int, std::multiplies<int>> f2 = std::multiplies<int>();
or this:
doer<int, std::multiplies<int>> f2{std::multiplies<int>()};

std::thread calling template function out of template function

I am trying to create threads out of a template function giving the thread another template function.
I have appended an expample of the situation that gives the same errors. Giving the thread a function that is not templated (ie here one with int and one with float) does not result in an error.
However since I plan to use this function with many different types I don't want to specify the template types. Also I have tried several specifyings of the template type (eg std::thread<T> or std::thread(function<T>) without any success.
Question: How can I call a template function with a std:thread out of a template function?
The following is a minimum compiling example of the situation, in reality the templates are own classes:
#include <thread>
#include <string>
#include <iostream>
template<class T>
void print(T* value, std::string text)
{
std::cout << "value: " << *value << std::endl;
std::cout << text << std::endl;
}
template<class T>
void threadPool(T* value)
{
std::string text = "this is a text with " + std::to_string(*value);
std::thread(&print, value, text);
}
int main(void)
{
unsigned int a = 1;
float b = 2.5;
threadPool<unsigned int>(&a);
threadPool<float>(&b);
}
compiling this example with g++ or icc with:
icc -Wall -g3 -std=c++11 -O0 -pthread
gives the folowing error messages (icc):
test.cpp(17): error: no instance of constructor "std::thread::thread" matches the argument list
argument types are: (<unknown-type>, unsigned int *, std::string)
std::thread(&print, value, text);
^
detected during instantiation of "void threadPool(T *) [with T=unsigned int]" at line 24
test.cpp(17): error: no instance of constructor "std::thread::thread" matches the argument list
argument types are: (<unknown-type>, float *, std::string)
std::thread(&print, value, text);
^
detected during instantiation of "void threadPool(T *) [with T=float]" at line 25
compilation aborted for test.cpp (code 2)
Thank you very much in advance
That's because just print is not a complete type.
I haven't tried it, but doing e.g. &print<T> should work.
Unrelated, but there's no need to pass pointers to your threadPool function. Passing a (possible constant) reference would probably be better.
Use this:
template<class T>
void threadPool(T* value)
{
std::string text = "this is a text with " + std::to_string(*value);
std::thread(&print<T>, value, text);
}
Try
std::thread([value,text]() { print(value, text); });