How can I use a C++11 to program the Arduino? - c++

How can I use C++11 when programming the Arduino?
I would be fine using either the Arduino IDE or another environment. I am most interested in the core language improvements, not things that require standard library changes.

As of version 1.6.6, the Arduino IDE enables C++11 by default.
For older versions, read on:
It is very easy to change the flags for any element of the toolchain, including the assembler, compiler, linker or archiver.
Tested on the Arduino IDE version 1.5.7 (released on July 2014),
Locate the platform.txt file,
AVR architecture => {install path}\hardware\arduino\avr\platform.txt
SAM architecture => {install path}\hardware\arduino\sam\platform.txt
Inside that file, you can change any flag, for instance,
compiler.c.flags for changing the default compilation flags for C++ files.
compiler.cpp.flags for changing the default compilation flags for C++ files.
You can also change any of the "recipes" or compile patters, at the corresponding section of the configuration file, under the title "AVR/SAM compile patterns".
After making the changes, you must restart the Arduino IDE, at least on version 1.5.7.
For instance,
To enable support for C++11 (C++0x), tested on Arduino IDE versions 1.5.7 and 1.5.8, you will simply add the flag "-std=gnu++11" at the end of the line starting with compiler.cpp.flags=".
It is expected that C++11 is enabled by default in the near future on the Arduino IDE. However, as of version 1.5.8 (Oct 2014) it is still not the case.

Arduino IDE 1.6.6 and newer have C++11 enabled by default (they have the compiler flag "-std=gnu++11" set in the platform.txt file).

Firstly, only GCC 4.7 and above (and therefore AVR-GCC 4.7 and above) support C++11. So, check the versions installed with:
gcc --version
avr-gcc --version
If AVR-GCC is 4.7 or higher, then you may be able to use C++11.
The Arduino IDE does not support custom compiler flags. This has been requested, but has not yet been implemented.
So, you are left with having to use other environments or to compile your program directly from the command line.
In case, of compiling directly from the command line using AVR-GCC, you simply need to add an extra compiler flag for enabling C++11 support.
-std=c++11
For specific development environments, most would support editing of the compiler flags from the build options within the IDE. The above mentioned flag needs to be added to the list of flags for each environment.
C++0x was the name of working draft of the C++11 standard. C++0x support is available GCC 4.3 onwards. However, this is strictly experimental support so you cannot reliably expect C++11 features to be present. Here is the complete list of features available with the corresponding version of GCC. The availability of features in AVR-GCC will be the same as what's available in the corresponding GCC version.
The compiler flag for C++0x is:
-std=c++0x

Please, note, that there is no easy way to specify additional flags from Arduino IDE or use other IDE (Eclipse, Code::Blocks, etc.) or command line.
As a hack, you can use a small proxy program (should be cross-platform):
//============================================================================
// Name : gcc-proxy.cpp
// Copyright : Use as you want
// Description : Based on http://stackoverflow.com/questions/5846934/how-to-pass-a-vector-to-execvp
//============================================================================
#include <unistd.h>
#include <iostream>
#include <vector>
#include <fstream>
using namespace std;
int main(int argc, char *argv[]) {
vector<string> arguments;
vector<const char*> aptrs;
// Additional options, one per line
ifstream cfg((string(argv[0]) + ".ini").c_str());
if (cfg.bad())
cerr << "Could not open ini file (you're using proxy for some reason, er?)" << endl;
string arg;
while (cfg) {
getline(cfg, arg);
if(arg == "\r" || arg == "\n")
continue;
arguments.push_back(arg);
}
for (const string& arg : arguments)
aptrs.push_back(arg.c_str());
for (int i = 1; i < argc; ++i)
aptrs.push_back(argv[i]);
// Add null pointer at the end, execvp expects NULL as last element
aptrs.push_back(nullptr);
// Pass the vector's internal array to execvp
const char **command = &aptrs[0];
return execvp(command[0], command);
}
Compile the program.
Rename the original avr-g++.exe to avr-g++.orig.exe (or any other name).
Create avr-g++.ini file where the first line is FULL path to the original program (e.g. D:\Arduino\hardware\tools\avr\bin\avr-g++.orig.exe) and add additional parameters, one per line, as desired.
You're done!
Example avr-g++.ini:
D:\Arduino\hardware\tools\avr\bin\avr-g++.orig.exe
-std=c++0x

I use Ino and this worked:
ino build -cppflags="-std=c++0x"
This generated a hex file at least 15k in size (that's with optimizations turned on), compared to about 5k for the standard build, which is a consideration for a poor little ATmega328. It might be okay for one of the microcontrollers with a lot more program space.

If you need more control and a better IDE, I recommend using Sloeber Plugin for Eclipse or the Sloeber IDE itself.
Creating more complicated code is much easier using this IDE. It also allows to add flags to the compiler (C, C++ and linker). So to customize the compile, just right click on project and select Properties. In the Properties window, select Arduino → Compiler Option. This way you can add options to your build.

Related

VSCode C++ Intellisense can't discern C++20 features

I try to run codes like
#include <string>
#include <iostream>
int main() {
std::string str = "This is a string";
std::cout << str.starts_with("name");
}
But intellisense will give out an error
"std::__cxx11::basic_string<char, std::char_traits,
std::allocator>" has no member "starts_with" C/C++(135) [6,9]
And It still can be build and produce a correct result.
Also it can find implementation in header file.
But the macro __cplusplus is defined as 201703L
I've already added a command -std=c++20 when building, why this happened?
Compiler: minGW 11.2 compiled by msys2
Assuming you are using Microsoft's C/C++ extension, you must configure the extension to use C++ 20 standard for intellisense.
The easiest way to do this is to add the line "C_Cpp.default.cppStandard": "c++20" to your settings.json file. You can also find the setting in the GUI under the name "Cpp Standard". Selecting c++20 from its dropdown will achieve the same result.
Note that this setting is, by default, set as a global user defaults. You can configure it per-workspace by selecting the Workspace tab in the settings GUI and changing that Cpp Standard dropdown to c++20.
As for why adding the -std=c++20 flag didn't work: -std=c++20 just tells your compiler which standard to use to build your code. 'Intellisense' does not receive this flag because it is a separate tool from the compiler and is therefore not required to support all the standards the compiler supports. It may support less even, although Intellisense tools usually support as current a standard as possible. Therefore the language standard for Intellisense must be configured separately from the compiler (in this case).
Final Note: After changing the setting, try closing and re-opening VS Code. In my experience changing the language standard setting can cause some weirdness to happen. Closing and re-opening VS Code seems to ensure the setting changes take full effect.

Warning: range-based for loop is a C++11 extension

While trying to compile a simple range based for loop on MacOS Big Sur, I got this warning:
warning: range-based for loop is a C++11 extension [-Wc++11-extensions]
I tried using clang++ and g++ but both gave the same warning. Is there a way to always compile with C++11 without having to use -std=c++11 and without using aliases?
Edit: The reason I would prefer not to use -std=c++11 is because I want the compiler to default to C++11 or higher.
To provide this question with a proper answer, based on the discussion in the comments:
Compilers such as GCC and Clang set the default in their source code and it cannot be changed by, e.g., modifying a config file. The only way to change the default would be to change it in the source code and to compile the compiler yourself. This is not worth it.
Furthermore, compilers change their default language from time to time, and setting another default, e.g. to C++11, will make all non-C++11 code require setting the language version explicitly.
Here's the key point: code and compilation options belong together. Do not rely on compiler defaults. Any serious project will use a build system (e.g. Make) which specifies how to compile the project.
Edit
For completeness sake, the default C++ version for GCC 10.2.0 is hardcoded in /gcc/c-family/c-opts.c:
/* Set C++ standard to C++17 if not specified on the command line. */
if (c_dialect_cxx ())
set_std_cxx17 (/*ISO*/false);

How to enable C++17 code generation in VS2019 CUDA project

I am moving some code from VS2017 on one pc to another pc with VS2019. Everything is fine excepted that I cannot use std::filesystem. In my former code, I was using C++14 and had std::experimental::filesystem. In the new code, I want to move to C++17 so I changed to std::filesystem (as shown in my code below). The weird thing is that intellisense (not sure it is the right name of the thing) shows no error. It even displays filesystem when I type std::f...
But the code won't build and give the error "namespace "std" has no member "filesystem"".
I changed C++ Language Standard to c++latest, VS2019 version is Community 16.6.5.
#include <string>
#include <iostream>
#include <filesystem>
namespace fs = std::filesystem;
int main()
{
std::string path = "C:\\";
for (const auto& entry : fs::directory_iterator(path))
std::cout << entry.path() << std::endl;
}
EDIT: The last line of my initial question might not have been clear enough: I already changed "C++ Language Standard" to C++17 or C++latest.
EDIT: As requested, the output:
Thanks to #drescherjm, we found that it is a Cuda issue. Any idea from a Cuda specialist?
Using CUDA 11, the nvcc compiler-driver is capable of supporting usage of certain C++17 language features. Currently, in VS2019, this doesn't appear to be the default behavior.
The following method should work to enable C++17 support when compiling a cuda project in VS2019:
go to Project..Properties..Configuration Properties...CUDA C/C++...Command Line Then you will see a box in the right hand side bottom of the dialog labelled "Additional Options". In that box, type the following:
-std=c++17 -Xcompiler "/std:c++17"
then click "Apply" then rebuild.
(These instructions may change for future versions of CUDA or future versions of Visual Studio.)
Note that this method applies to CUDA projects only (i.e. when nvcc is invoked for compilation), and should be workable whether your code is in a file ending in .cpp or in a file ending in .cu. For non-CUDA projects, this may be helpful.
The std::filesystem features appear to require C++17. The CUDA nvcc compiler-driver is documented here.

How to make sure code (c++) written in Xcode can compile on other platforms?

I am a beginner was trying to do some C++ programming on Xcode. It works fine, but when I try to compile the same c++ file on my windows pc using VS, there were some errors. After I look at my code closely, there are really some stupid mistakes that I have made which caused the errors, but Xcode seemed to have ignored them...
My question is that is there any setting that I need to change to prevent Xcode from being so smart?
For example, the following code can actually compile in xcode:
#include <iostream>
using namespace std;
int main() {
if (true or false){
cout << "How is this possible? \n";
}
return 0;
}
There are also other cases where the code is actually wrong, but it can compile just fine is Xcode which is the annoying part and I want to disable that.
As far as I can see there is nothing wrong with your code.
The ISO C++ standard does not specify which standard headers are included by other standard headers. So, it is entirely possible that the version of iostream used by Xcode directly or indirectly includes ciso646. Whereas Visual Studio's version of iostream does not include ciso646. There are many similar cases with other headers. You just need to read the error messages and realize that your error (when you move your file to a different platform) is due to a missing header file.
It would be nice if writing portable code meant writing code in accordance with the C++ standard specification, but unfortunately that's not the case. Although there are various compiler options on various implementations which can help bring different implementations closer together, in general you will just have to bring the code into the target environment and actually test it there.
So ultimately writing portable code means you'll have to learn some subset of C++ that is accepted by all the implementations you want to target.
or is an 'alternative token' in C++, and VS is incorrect to reject it. There's no option in Xcode to disable support for alternative tokens. However VS has non-standard support for or as a macro using the header <ciso646>, and Xcode does have a header <ciso646> which does nothing (as the standard specifies). So you can write code which uses or and which works in both Xcode and VS by including this header.
#include <iostream>
#include <ciso646> // does nothing in Xcode, allows `or` in VS
using namespace std;
int main() {
if (true or false){
cout << "How is this possible? \n";
}
return 0;
}
Unfortunately VS can't support all of the alternative tokens through macros and so Xcode will still support some that VS doesn't.
There are also other cases where the code is actually wrong, but it can compile just fine is Xcode which is the annoying part and I want to disable that.
If you give specific examples then I can provide additional advice on how to write portable code.
Rather than changing your Xcode settings, I suggest cross-checking your code using another development environment.
If you're looking for something cheap and full-proof. Download a VirtualBox Windows VM, and run download Dev C++ (bloodhshed)
VS does not support or: you need to use || instead.
You can include some special files but it doesn't inject or sufficiently well into the language for it to work in all instances.
If you want to suppress use of or (and your compiler supports no better way)
#define it to something that emits a compiler error, for example
#define or OR
This at least means that the nature of the compilation errors will be identical on Xcode and VC.

Orwell Dev C++ doesn't work with C++11

I'm trying to use any of the C++11 features in Orwell Dev C++ but with no luck. I installed the version with minGW and whatever I set in the compiler options, I just get the "[Error] 'to_string' was not declared in this scope" in this code:
#include<iostream>
#include<string>
using namespace std;
int main()
{
string test = to_string(5);
}
I tried setting -std=gnu++11 and -std=c++0x but neither does the job. What's the most curious is that when I click on to_string, it shows me the overloaded functions - for long, float, int and so on. Thus, it must somehow get what the function does - how come it doesn't compile it, then? The compiler is set correctly to MinGW GCC 4.7.2 (the one bundled with the installer).
If you want to use C++11 in Dev-C++ you should to this steps:
Go to Tools > Compiler Options
Go to the tab Settings > Code Generation
Change the parameter Language Standard (-std) to ISO C++11
It is a known bug that to_string does not work with MinGW yet (which is actually GCC's fault, to a degree):
http://sourceforge.net/p/mingw/bugs/1578/
http://gcc.gnu.org/bugzilla/show_bug.cgi?id=52015
Intellisense is often driven by a different engine than the compiler (as very few compilers have hooks to make intellisense easy), so that's likely why you're seeing it in your IDE when it's not supported by your compiler.