I am trying to launch a function threaded using launch::async. However, I noticed that this doesn't work when passing struct elements as parameter:
The code
#include <future>
#include <vector>
#include <thread>
struct example { int ten; };
void threadFunction(int number, std::string hi) {
printf("%s Your number is %d\n", hi.c_str(), number + 1);
}
int main() {
example ex;
ex.ten = 9;
std::string someString = "Hi there!";
std::vector< std::future< void > > threads(5);
for (uint16_t s = 0; s < 5; s += 1) {
threads[s] = async(std::launch::async,
[ex.ten,
someString] {
threadFunction(ex.ten, someString);
});
}
}
gives the following errors:
file.cpp: In function ‘int main()’:
file.cpp:25:39: error: expected ‘,’ before ‘.’ token
[ex.ten,
^
file.cpp:25:39: error: expected identifier before ‘.’ token
file.cpp:25:43: error: expected ‘]’ before ‘,’ token
[ex.ten,
^
file.cpp: In lambda function:
file.cpp:25:43: error: expected ‘{’ before ‘,’ token
file.cpp: In function ‘int main()’:
file.cpp:26:46: error: expected ‘)’ before ‘]’ token
someString] {
^
file.cpp:28:8: error: expected primary-expression before ‘)’ token
});
When replacing ex.ten with some other variable ten it does work.
So my questions are:
1. Why does launch::async not work with struct elements?
2. Is there a way to do it in a more elegant way than to make a variable for each element in the struct and pass those variables instead? (such as int ten = ex.ten; etc)
You can't pass single struct field that way into lambda in C++. The error you get is not connected to std::launch or communicating between threads. What you can do instead is:
C++11 - copy field into local variable and capture that variable:
auto ten = ex.ten;
threads[s] = async(std::launch::async,
[ten,
someString] {
threadFunction(ten, someString);})
C++14 and later - initialize variable in capture list:
threads[s] = async(std::launch::async,
[ten = ex.ten,
someString] {threadFunction(ten, someString);})
What you are trying to do is to capture a field in the struct in lambda. This is not possible, you can only capture the whole struct.
It has nothing to do with std::launch, it's a basic property of lambda closure.
In C++14, you can have captures with initializers, which might be what you want:
auto lam = [ten = ex.ten]...
Related
I am trying to initialize struct sigaction (from sigaction.h) using C++20 designated initializers, but there are compiler errors. As this is part of a larger program, I created a short example:
#include <stdio.h>
#include <unistd.h>
#include <signal.h>
void onSIGINT(int signal, siginfo_t *siginfo, void *context) {
printf("Caught signal\n");
}
int main(int argc, char** argv) {
struct sigaction act = {
.sa_sigaction = onSIGINT,
.sa_flags = SA_SIGINFO
};
if(sigaction(SIGINT, &act, nullptr) != 0) {
fprintf(stderr, "Failed to listen for SIGINT\n");
return 1;
}
printf("Waiting for signal...\n");
pause();
printf("Exit\n");
return 0;
}
According to https://gcc.gnu.org/projects/cxx-status.html#cxx20 designated initializers are available in gcc8. Running g++ (v8.3.0 on Debian buster) with -std=c++2a gives the following error:
main.cpp: In function ‘int main(int, char**)’:
main.cpp:11:9: error: expected primary-expression before ‘.’ token
.sa_sigaction = onSIGINT,
^
main.cpp:12:9: error: either all initializer clauses should be designated or none of them should be
.sa_flags = SA_SIGINFO
^
Initializing only sa_flags compiles successfully, initializing only sa_sigaction fails to compile (only first error).
I also tried to initialize __sigaction_handler directly (no using the define to access the union member):
struct sigaction act = {
.__sigaction_handler = { .sa_sigaction = onSIGINT },
.sa_flags = SA_SIGINFO
};
That produces a similar error:
main.cpp: In function ‘int main(int, char**)’:
main.cpp:12:34: error: expected primary-expression before ‘.’ token
.__sigaction_handler = { .sa_sigaction = onSIGINT },
^
I suppose I am doing something wrong about the union inside the struct, but I can't figure out what.
I am aware that I could achieve roughly the same by zeroing the memory of the struct and then setting callback and flags, but thats not the point.
The problem is that sa_sigaction is a macro, defined to __sigaction_handler.sa_sigaction. This means that your code expands to .__sigaction_handler.sa_sigaction = onSIGINT; this is valid C, where a named member initializer is allowed to have a complex structure, but it is not valid in C++20.
You can see that by #undefing it:
#undef sa_sigaction
.__sigaction_handler = { .sa_sigaction = onSIGINT },
However this is non-portable (undefining a standard library macro, not to mention using a double-underscore prefixed member), so I would recommend against it.
I am getting this error during compile time (g++ 4.4.6):
main.cpp: In function ‘int main()’:
main.cpp:27: error: expected initializer before ‘:’ token
main.cpp:33: error: expected primary-expression before ‘for’
main.cpp:33: error: expected ‘;’ before ‘for’
main.cpp:33: error: expected primary-expression before ‘for’
main.cpp:33: error: expected ‘)’ before ‘for’
main.cpp:33: error: expected initializer before ‘:’ token
main.cpp:36: error: could not convert ‘((list != 0u) ? (list->SortedList::~SortedList(), operator delete(((void*)list))) : 0)’ to ‘bool’
main.cpp:37: error: expected primary-expression before ‘return’
main.cpp:37: error: expected ‘)’ before ‘return’
My code is as follows:
#include <iostream>
#include "Student.h"
#include "SortedList.h"
using namespace std;
int main() {
SortedList *list = new SortedList();
Student create[100];
int num = 100000;
for (Student &x : create) { // <--Line 27
x = new Student(num);
num += 10;
}
for (Student &x : create)
list->insert(&x);
delete list;
return 0;
}
Anybody who possibly knows the source of the error would be of great help. Also, Student and SortedList are objects which are declared in their .h files.
According to this page on GCC's website, range-based for is only available in g++ 4.6 and up, so you'll have to convert your code to a normal for loop or use std::for_each or something, or upgrade your compiler.
This question is related to the one discussed here.
I try to use an initializer list to create an argument to be passed to operator[].
#include <string>
#include <vector>
struct A {
std::string& operator[](std::vector<std::string> vec)
{
return vec.front();
}
};
int main()
{
// ok
std::vector<std::string> vec {"hello", "world", "test"};
A a;
// error: could not convert '{"hello", "world", "test"}' to 'std::vector...'
a[ {"hello", "world", "test"} ];
}
My Compiler (GCC 4.6.1) complains:
g++ -std=c++0x test.cpp
test.cpp: In function ‘int main()’:
test.cpp:20:8: error: expected primary-expression before ‘{’ token
test.cpp:20:8: error: expected ‘]’ before ‘{’ token
test.cpp:20:8: error: expected ‘;’ before ‘{’ token
test.cpp:20:35: error: expected primary-expression before ‘]’ token
test.cpp:20:35: error: expected ‘;’ before ‘]’ token
Should this be valid C++11?
Interestingly, when using operator() instead of operator[] it works.
Yes, it is valid C++11 and should work in any compliant compiler.
Please note that C++11 support in gcc is quite immature, and this code example will not compile in any 4.6 version, but only in 4.7 svn snapshot versions.
I am trying to cin a loop index's value in the loop itself using lambda expression:
#include<iostream>
using namespace std;
int main(){
for(int a, ([](int & b){cin>>b;})(a); a < 2; ++a);
return 0;
}
These are the errors when i compile using g++ 4.5 on ubuntu:
forLoopAndCinTest.c++: In function ‘int main()’:
forLoopAndCinTest.c++:5:14: error: expected unqualified-id before ‘[’ token
forLoopAndCinTest.c++:5:14: error: expected ‘)’ before ‘[’ token
forLoopAndCinTest.c++:5:34: error: expected primary-expression before ‘)’ token
forLoopAndCinTest.c++:5:34: error: expected ‘;’ before ‘)’ token
forLoopAndCinTest.c++:5:40: error: name lookup of ‘a’ changed for ISO ‘for’ scoping
forLoopAndCinTest.c++:5:40: note: (if you use ‘-fpermissive’ G++ will accept your code)
forLoopAndCinTest.c++:5:50: error: expected ‘;’ before ‘)’ token
If i use a normal function instead of the lambda, program compiles fine.
Using -fpermissive doesnt help either.
Any ideas?
That's not how the for look works. You are trying to call a lambda where the compiler expects you to declare an int:
for( int a, int2, ...; a < 2; ++a );
Now,
If i use a normal function instead of
the lambda, program compiles fine
Yes, but it's probably not doing what you think it does.
void f(int& b)
{
cin >> b;
}
// ...
for( int a, f(a); a < 2; ++a );
Here, the loop declares two int variables, named a and f. The loop doesn't call f() as you might expect.
Try this instead:
for( int a; cin >> a && a < 2; ++a );
The first part of the for is interpreted as a declaration. We get the very same error when replacing your code by the (almost) equivalent :
int main(){
int a, ([](int & b){cin>>b;})(a); // This produces the same error
for(; a < 2; ++a);
return 0;
}
To answer a comment you made, for (int a, foo() ; ... works, but not like you think it does. It is in fact declaring a function (inside the for scope) that returns an int, and has the name foo. As in :
int a, foo();
Which you should read as :
int a;
int foo();
After this: for( int a, compiler expects some name (of the variable) - unqualified-id.
But in your case it is not so.
This is the program I'm trying to compile.
#include <iostream>
#include <string>
#include <vector>
#include <unistd.h>
using namespace std;
vector<string> paramlist;
const char *programname = "abc";
const char **args = new const char* [paramlist.size()+2]; // extra room for program name and sentinel
args [0] = programname; // by convention, args[0] is program name
for (int j = 0; j < paramlist.size()+1; ++j) // copy args
args [j+1] = paramlist[j] .c_str();
args [paramlist.size()+1] = NULL; // end of arguments sentinel is NULL
execv (programname, (char **)args);
When I try to compile it I get these error messages:
test.cpp:11: error: expected constructor, destructor, or type conversion before ‘=’ token
test.cpp:12: error: expected unqualified-id before ‘for’
test.cpp:12: error: expected constructor, destructor, or type conversion before ‘<’ token
test.cpp:12: error: expected unqualified-id before ‘++’ token
test.cpp:15: error: array bound is not an integer constant
test.cpp:15: error: expected constructor, destructor, or type conversion before ‘=’ token
test.cpp:17: error: expected constructor, destructor, or type conversion before ‘(’ token
You at least need an int main function.
Your program contains code but it needs to be contained within a function. Try wrapping all your code after the using namespace std; line with a function like int main. Google for any "Hello world" C++ sample to see an example.