Is mixing modules and headers in C++20 possible / acceptable? - c++

I'm actually trying to understand the C++20 modules system by writing my own little module. Let's say I want to provide a function that deletes all the spaces at the beginning and the end of a string (a trim function). The following code works without problem.
module;
export module String;
import std.core;
export std::string delete_all_spaces(std::string const & string)
{
std::string copy { string };
auto first_non_space { std::find_if_not(std::begin(copy), std::end(copy), isspace) };
copy.erase(std::begin(copy), first_non_space);
std::reverse(std::begin(copy), std::end(copy));
first_non_space = std::find_if_not(std::begin(copy), std::end(copy), isspace);
copy.erase(std::begin(copy), first_non_space);
std::reverse(std::begin(copy), std::end(copy));
return copy;
}
import std.core;
import String;
int main()
{
std::cout << delete_all_spaces(" Hello World! \n");
return 0;
}
But what if I want to use only specific headers instead of std.core in my module? If I do so, replacing the import std.core by the following code, I get an error on Visual Studio 2019.
module;
#include <algorithm>
#include <cctype>
#include <string>
export module String;
// No more import of std.core
export std::string delete_all_spaces(std::string const & string)
{
// ...
}
Error LNK1179 file not valid or damaged: '??$_Deallocate#$07$0A##std##YAXPAXI#Z' COMDAT duplicated
However, if in the main.cpp I remplace as well the import std.core with #include <iostream>, the code compiles again. It's like using both system provents the linker to do its job.
The question is: am I doing it wrong? Is it a bad practice to use both the new import and the old #include methods? I saw on multiple posts on the Internet that you can include some old headers in your module, thus modernizing your code without breaking the existing. But what if this header includes some part of the STL, like #include <string> but my module uses import std.core?
I'm testing only with Visual Studio 2019 because, as of now, import std.core does not work with GCC. So, may it comes from a bug in VS? Or will the problem be the same for all compilers?

Yes, modules can be used together with header files. we can both import and include headers in the same file, this is an example:
import <iostream>
#include <vector>
int main()
{
std::vector<int> v{1,6,8,7};
for (auto i:v)
std::cout<<i;
return 0;
}
When you create modules, you're free to export entities in the interface file of the module and move the implementations to other files. to conclude, the logic is the same as in managing .h and .cpp files

Related

C++20 Modules std.ixx STL Static/Global Scope References

Following instructions by Microsoft, I couldn't get the std module to build and not have a versioning error, so I went ahead and just added the file:
C:\Program Files\Microsoft Visual Studio\2022\Preview\VC\Tools\MSVC\14.35.32213\modules\std.ixx
to my project and I import it into my module interface files. My only issue is I can't access ::localtime_s because it is one of the static-inline/global functions not in the std namespace. Including <time.h> in the global module space creates issues with macro redefinitions. Is there something I am missing?
export module MyModule;
import std;
export namespace nspace1 {
void TimeFunction();
}
namespace nspace1 {
void TimeFunction()
{
std::time_t t = std::time(nullptr);
std::tm* now{};
void* result = ::localtime_s(now, &t); <== dne
}
}
The intellisense error is it is not found in the global space which makes sense for localtime_s because it is static, but _localtime64_s is just global and it says the same thing. Dropping the double colons just changes the error message to cannot be found.
The following code builds ok on my machine.
(Version 17.5.0 Preview 3.0)
import std; is a C++23 feature. I hope vendor support is getting better.
module;
#include <time.h>
export module MyModule;
import std;
export namespace nspace1 {
void TimeFunction();
}
namespace nspace1 {
void TimeFunction()
{
std::time_t t = std::time(nullptr);
std::tm* now{};
auto result = ::localtime_s(now, &t);
//auto result = localtime_s(now, &t); // ok, too
}
}

Understanding Preprocessor Directives in C++ as a beginner

I recently began learning C++. As a programmer coming from Python, I've noticed some general similarities when it comes to how certain things in C++ do the same thing over in Python.
One question I had is understanding Preprocessor directives. I/O Stream seems to be a common one to use in beginner programs.
Is #include effectively the same thing as import in Python, or is it completely different than importing "modules"?
C++ did not have modules until the latest standard (C++20). #include is not the same as import in the languages that support modules. Instead, it is a source code - level inclusion of a "header" file. Usually, the headers only contain declarations but not definitions of what you are "importing". The definitions are contained in compiled libraries that are added by the linker.
Congrats on diving in to C++, you're going to have many more questions and confusions coming from Python, especially if you use some of the newer standards (like C++11/14/17/20).
That aside, answering your question directly:
Is #include effectively the same thing as import in Python or is it completely different than importing "modules."
I won't speak to C++20 modules as that functionality is not fully supported across the various compilers and that is not your question. Unfortunately the answer is not a simple yes or no, it's kind of both.
In C and C++, the #include pre-processor directive essentially does a "copy-paste" of whatever file you #include before it does the compilation stage. This allows you to separate large chunks of code into easier to manage files and still reference the code in said file.
In Python/C#/Java and various other languages, you don't #include a file you want to access the classes and functions of, you import the namespace or module you wish to reference and the JIT compiler "knows" which file that module or namespace is in, allowing you to use the functionality of the code in that file.
Python and C++ don't "build" the code in the same way and thus don't reference parts of the source code in the same way.
To illustrate this point more succinctly, take the following C++ code:
file: fun.hpp
#define FUN_NUM 1
namespace fun
{
int get_fun()
{
return FUN_NUM;
}
}
file: main.cpp
#include <iostream>
#include "fun.hpp"
int main(int argc, char* argvp[])
{
if (fun::get_fun() == FUN_NUM) {
std::cout << "Fun!" << std::endl;
}
return FUN_NUM;
}
In the above code, when we #include "fun.hpp", what the C++ pre-processor does before compiling is essentially "copy-and-paste" the code in iostream and fun.hpp, so what actually gets compiled is something like the following:
file: main.cpp
// #include <iostream> <- this is replaced with the whole std::iostream file
// not putting that here as it's huge.
// #include "fun.hpp" <- this is replaced with this:
#define FUN_NUM 1
namespace fun
{
int get_fun()
{
return FUN_NUM;
}
}
int main(int argc, char* argvp[])
{
if (fun::get_fun() == FUN_NUM) {
std::cout << "Fun!" << std::endl;
}
return FUN_NUM;
}
It is because of this "copy-paste" that you also need to have include guards, because if you did something like the following:
file: main.cpp
#include <iostream>
#include "fun.hpp"
#include "fun.hpp"
int main(int argc, char* argvp[])
{
if (fun::get_fun() == FUN_NUM) {
std::cout << "Fun!" << std::endl;
}
return FUN_NUM;
}
This code won't compile because you'll get errors about various items being redeclared since what gets compiled is the following:
file: main.cpp
// #include <iostream> <- this is replaced with the whole std::iostream file
// not putting that here as it's huge.
// #include "fun.hpp" <- this is replaced with this:
#define FUN_NUM 1
namespace fun
{
int get_fun()
{
return FUN_NUM;
}
}
// #include "fun.hpp" <- this is replaced with this:
#define FUN_NUM 1
namespace fun
{
int get_fun()
{
return FUN_NUM;
}
}
int main(int argc, char* argvp[])
{
if (fun::get_fun() == FUN_NUM) {
std::cout << "Fun!" << std::endl;
}
return FUN_NUM;
}
To protect from the double inclusion and redefinition, you can simply do something like the following:
file: fun.hpp
#if !defined(FUN_HPP)
#define FUN_HPP
#define FUN_NUM 1
namespace fun
{
int get_fun()
{
return FUN_NUM;
}
}
#endif // define FUN_HPP
So unless you pass FUN_HPP as a pre-processor define to the compiler, then FUN_HPP will not be defined until the file is #include'd once, then any other times it's included, FUN_HPP will already be defined and thus the pre-processor will not include the code again, ridding the problem of double-definitions.
So where your question is concerned, the #include directive in C++ is somewhat like the import directive in Python, but mostly to the effect that they both allow the file you are putting that directive in, to access code more directly from that import or #include.
I hope that can add a little clarity.

Why does my program compile successfully if I don't include <string.h>?

I've been puzzled by this for a while. To test this out, I made a simple program that just creates a std::string variable and prints it out to the screen. However, it doesn't include <string.h>.
#include <iostream>
using namespace std;
int main()
{
string name = "Test";
cout << name << endl;
return 0;
}
What confuses me is that this program compiles and runs perfectly. Right now I'm using the clang compiler that came with the XCode Developer Tools. Is this intended behavior? I hope this question isn't too ridiculous since I just started learning C++.
The reason you do not need to include the #include <string.h> header file is because when you include the #include <iostream> header file it includes std::string.
However, do not rely on it. What may work on your compiler may not work on another. Always include the proper header files.
To edit your example this is how you should use it:
#include <iostream>
#include <string>
int main()
{
std::string name = "Test";
std::cout << name << std::endl;
return 0;
}
Also note: why you should not use using namespace std;.
Why does my program compile successfully if I don't include <string.h>?
Because you don't use any definition / declaration from <string.h>.
program compiles and runs perfectly ... Is this intended behavior?
It is incidental behaviour.
There are no guarantees that one standard header wouldn't include other standard headers. It just so happens that <iostream> included <string> in this particular version of the standard library. Since there is no guarantee for this, it would be a mistake to rely on such transitive inclusion.

How to include external library in your lib?

I am writing a library which itself uses a header-only 3rd-party library.
Currently, even if I build it as a static library, the client code still needs to add that 3rd-party library as well, as it is declared in my library's header file.
What can I do so that everything that's used by my code, ends up in the static library and the client code doesn't have to include what I have included in the header file?
There was a similar question, but the answer doesn't seem to work for me as I am building the static library with all of its dependencies (i.e. the include paths are configured and builds are successful).
To give you a better view, this is how my Core.h looks like:
#ifndef CORE_H
#define CORE_H
#include <iostream>
#include <string>
#include <vector>
#include <functional>
#include <pybind11/pybind11.h>
#include <pybind11/embed.h>
#include <pybind11/stl.h>
#include <pybind11/functional.h>
#include <pybind11/numpy.h>
namespace py = pybind11;
using namespace py::literals;
typedef void(*CallbackFn)(bool, std::string, py::array_t<uint8_t>&);
typedef std::function<void(std::string)> LogFunction;
class Core
{
private:
py::scoped_interpreter guard{};
py::object cls;
py::object obj;
py::object startFunc;
py::object stopFunc;
py::object setCpuAffinityFunc;
py::object addCallbackFunc;
py::object removeCallbackFunc;
py::object getCallbacksFunc;
py::dict kwargs;
py::list callbackList;
public:
Core();
Core(bool showFeed);
...
As you can see, the issue here is the Pybind11 header-only library which is used in my code. Unfortunately, since these #include statements are included in my header file, the client code also needs to add pybind11 to their project in order for their project to build.
Is there any other way, other than converting all the py::* to void* and then including the header files in the Core.cpp file?
I found a solution for you. Consider your case: Client uses a library which uses a third library.
This can be assimilated by the following solution:
Client : .exe project is the client who know only Core project
Core : .lib project uses ThirdParty (Header_lib project) and can be used by Client project
Header_lib project is the ThirdParty lib
Solution configuration:
- Client Project depend from Core project:
-Core project depend from Header_Lib project:
In code:
Client create an instance cc of CCore object.
cc call useCoreParty function.
useCoreParty function uses ThirdParty
When i export core.lib:
DUMPBIN /SYMBOLS "G:\Core.lib" | findstr "useThirdParty"
I get:
This means that thirdparty part is included in your core.lib. Therefore, the client does not need to include thirdpaty's libs
I ended up using forward declaration, but not for the Pybind11 classes.
This is what I ended up doing :
//header file
#ifndef CORE_H
#define CORE_H
#include <iostream>
#include <string>
#include <vector>
#include <functional>
struct Wapper;
class Core
{
private:
Wapper* cls;
Wapper* obj;
Wapper* startFunc;
Wapper* stopFunc;
...
public:
Core();
...
};
and in the implementation file :
#include <pybind11/pybind11.h>
...
namespace py = pybind11;
using namespace py::literals;
struct Wrapper
{
py::object obj;
};
py::scoped_interpreter guard{};
Core::Core()
{
this->cls = new PyWrapper();
this->obj = new PyWrapper();
...
auto serviceUtilsModule = py::module::import("Module");
this->cls->obj = serviceUtilsModule.attr("SomeClass");
...
this->obj->obj = this->cls->obj(**kwargs);
...
}
This hides the pybind11 dependency from the client code and achieves what I was after!
Basically I forward declared a new type, made a pointer out of it and defined it inside the core.cpp. and since I defined in core.cpp I have many choices one of which was to add a py::object inside it and use that instead.
Side note:
I noticed the client project had to include Python's include and library folders or otherwise, it will complain about not finding Pybind11! This is truly bizarre! but since the client code will be running in an environment that must have a python package installed, its not an issue!
However, I'd also like to know why this is happening !

When I split up my C++ class into a header and implementation I get 20 compiler errors which don't make sense

I was splitting up my program into a header and implementation file per usual, however, when I tried to run the code, I got a ton of compile errors. This seems to be an issue with my computer or IDE, but I have not seen it before. This should be relatively simple as it is for a class project.
The code is as follows:
colorPicker.h
#pragma once
class colorPicker {
private:
string colorArray[7];
public:
colorPicker();
void printAllColors();
string randomColor();
};
colorPicker.cpp
#include "colorPicker.h"
#include "stdafx.h"
#include <iostream>
#include <string>
#include <ctime>
#include <stdio.h>
#include <stdlib.h>
using namespace std;
colorPicker::colorPicker() {
colorArray[0] = "Red";
colorArray[1] = "Green";
colorArray[2] = "Purple";
colorArray[3] = "Yellow";
colorArray[4] = "Orange";
colorArray[5] = "Indigo";
colorArray[6] = "Pink";
}
void colorPicker::printAllColors() {
for (int i = 0; i < 7; i++) {
cout << colorArray[i] << endl;
}
}
string colorPicker::randomColor() {
srand((unsigned)time(0));
int j = 0;
j = rand() % 7;
return colorArray[j];
}
main.cpp
#include "colorPicker.h"
#include "stdafx.h"
#include <iostream>
#include <string>
#include <ctime>
#include <stdio.h>
#include <stdlib.h>
using namespace std;
int main() {
colorPicker p;
p.printAllColors();
cout << "Random Color: " << p.randomColor() << endl;
system("pause");
return 0;
}
There are 20 errors given by the compiler, however, they all seem to be stemming from two undeclared identifiers which are most definitely declared. I am at a loss for what I could possibly do to fix it, and this project is due Sunday. Thank you.
Here are the errors
Tons of Errors
You need #include "colorPicker.h" in colorPicker.cpp. Each .cpp file is handled basically independently by the compiler and they are all joined at the end by the "linker." When the compiler looks at colorPicker.cpp without an include of the corresponding header, it's at a loss as to the definition of all the classes you're working with.
There are a few things you are doing wrong. I'll just pick on a couple.
Firstly, each header file you write should be self-contained - in the sense that, if it relies on content of some other headers, it includes that header. If a compilation unit (a formal name for a source file with a .cpp in your case) includes your header, it should not have to include something else your header depends on.
Second, it is a bad idea for a header to rely on any using directive, such as using namespace std. There are plenty of explanations of that available, so I won't repeat.
To understand the above, look at colorPicker.h
class colorPicker {
private:
string colorArray[7];
public:
colorPicker();
void printAllColors();
string randomColor();
};
Firstly, this depends on string, but there is no definition of string visible in the header file. Usage of that type depends on the standard header <string>.
Second, that string type is within namespace std. So your header relies on the compilation unit (the source file that includes your header) having previously used a using directive i.e. using namespace std.
To fix these two problems, change the header to
#ifndef SOME_MACRO_UNIQUE_TO_YOUR_COLOR_PICKER_HEADER
#define SOME_MACRO_UNIQUE_TO_YOUR_COLOR_PICKER_HEADER
#include <string>
class colorPicker
{
private:
std::string colorArray[7];
public:
colorPicker();
void printAllColors();
std::string randomColor();
};
#endif
(I've also done some minor changes of layout, since I have various reasons to prefer that.
However, the #include <string> means that this version will not fail to compile, as yours does, if it is included by a compilation unit that does not have #include <string>.
The usage of the fully qualified name std::string, rather than string, also means there is no dependence on the using directive using namespace std. It also means compilation errors can't be triggered in your header if your compilation unit has another using directive.
I've also used an include guard, rather than #pragma once. Although most modern compilers support #pragma once, it is actually not standard C++ (a #pragma, by definition in the standard, is a compiler-specific hook). Include guards are supported in standard C++.
If you've done that, your code should mostly compile as is. However, optionally, you may wish to
remove the using directives using namespace std from your other files. If you do that, you will need to change the definition of colorPicker::randomColor() in colorPicker.cpp so it returns the fully qualified type std::string rather than string.
Remove #include <string> from files that have #include "colorPicker.h". This is possible, since colorPicker.h now includes <string>. This step is optional, since there is no problem with including standard headers more than once in a compilation unit.
A few other notes
In C++, although it is not a major concern, it is usually considered better to use include <cstdio> and <cstdlib> rather than the C headers <stdio.h> and <stdlib.h>.
Your code is calling srand((unsigned)time(0)) whenever colorPicker::randomColor() is called. It is better to only call it once in an entire program, not in a function that may be called multiple times.
A header file should be self-contained as far as #includes go. That means that you should be able to #include the header file without having to include other stuff before it!
Your colorPicker.h does not meet that requirement. It apparently uses std::string from the standard library but does not have an #include <string> on top, so everyone who uses colorPicker.h has to remember to put an #include <string> before it. That's pretty annoying.
Even worse, colorPicker.h refers to std::string as string, which implies a using std::string; or using namespace std; somewhere before any #include "colorPicker.h" line, and both of those are very bad coding style in C++, if not used in tighter scopes.
Here's how to fix the header file:
#pragma once
#include <string>
class colorPicker {
private:
std::string colorArray[7];
public:
colorPicker();
void printAllColors();
std::string randomColor();
};
As far as your *.cpp files go, I can see that you are using #include "stdafx.h". Why? It's a non-standard Microsoft thing completely unnecessary in your case. You are also using it incorrectly. It must be the first include. Just remove it entirely.
Some other suggested cleanup:
using namespace std; lines in *.cpp files is not as bad as in header files, but if I were you, I'd just get rid of it completely. Just use complete names. Say std::cout, not cout. And so on. It's just the most consistent way and it avoids a lot of trouble.
You include a lot of headers which you don't need. For example, what's <ctime> for?
Don't use system("pause");. Do not look for artificial ways of pausing a command-line program.
You may need add head file and in colorPicker.h.
And the std namespace is needed while using string.
BTW, the header guards is recommended strongly.
#ifndef COLOR_PICKER_H
#define COLOR_PICKER_H
#pragma once
#include <string>
class colorPicker {
private:
std::string colorArray[7];
public:
colorPicker();
void printAllColors();
std::string randomColor();
};
#endif