When to use c++ module? - c++

This question might be too broad but it really tickled my mind lately:
I recently found out about modules in modern C++ : https://en.cppreference.com/w/cpp/language/modules
But I really don't get their purpose and when to use it instead of namespaces or just library headers?
In the example provided they now use import <iostream>; instead of include <iostream>;, what is the the difference in using one versus the other? Which one is to be preferred?
They say that "module are orthogonal to namespaces"? What does this mean?
What are the guidelines regarding development, should we now avoid headers and stuff ?
For instance:
helloworld.cpp
export module helloworld; // module declaration
import <iostream>; // import declaration
export void hello() // export declaration
{
std::cout << "Hello world!\n";
}
main.cpp
import helloworld; // import declaration
int main()
{
hello();
}
VERSUS
helloworld.h / helloworld.cpp
include <iostream>;
namespace ns
{
void hello();
}
#include "helloworld.h";
void ns::hello()
{
std::cout << "Hello world!\n";
}
main.cpp
#include "helloworld.h";
int main()
{
ns::hello(); // optionally "using namespace ns; to avoid ns::"
}

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
}
}

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

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

How to extend an assigned namespace

I want to explain my question over an instance. I am using an third party library, having its own namespace. I want to import a part of this library, having its own namespace inside the namespace mentioned below.
namespace library {
namespace part {
}
}
There is also a hierarchy in the current project. I want to import and extend the library::part inside to my project with another name. I try to do as below:
#include <library/part>
namespace project {
namespace my_part = library::part;
}
namespace project {
namespace my_part {
void my_extension_1();
void my_extension_2();
}
}
The scenario can be done with the current tools of the language? If not, how should a workaround can be done? Still not, why?
Edit: Error message gcc 5.3.0 dumps:
error: conflicting declaration of namespace ‘project::my_part’
Edit: There is a suggestion about extending the original namespace, but that I am asking for. library::part users should not have a direct access to the functions I have added.
I believe you want to make a namespace of your own that contains
everything that library::part contains, and more besides, without
putting anything more into library::part. Like this?
namespace library {
namespace part {
const int library_part_i = 123;
}
}
namespace project {
namespace part {
using namespace library::part;
void my_extension_1(){};
void my_extension_2(){};
}
}
int main()
{
// const int i = library_part_i; <- Does not compile
// const int i = project::library_part_i; <- Does not compile
const int i = project::part::library_part_i;
// library::part::my_extension_1(); <- Does not compile
project::part::my_extension_2();
return 0;
}

Comparing #include and using namespace std in C++ with import in Python

I read through many pages on the internet about the #include statement and using namespace std phrase in C++ and I need some clarification. Since I already know Python I will use it as an analogy. First of all, in C++
#include library
and in Python
import library
are the same. Then, in C++
#include library
using namespace std;
and in Python
from library import *
are the same.
For example, if we compare the first analogy, we know that in C++
#include <iostream>
int main()
{
std::cout << "hello" << std::endl;
return 0;
}
is similar to the code below in Python (similar in using std and #include):
import math
def main():
print math.sqrt(12)
If we were to compare the second analogy, we have that in C++
include <iostream>
using namespace std;
int main()
{
cout << "hello world" << endl;
}
and in Python
from math import *
def main():
print sqrt(12)
are similar.
Can you correct me if I am wrong?
#include is "copy-paste this file". For example, you can #include a file into itself, and get this ridiculousness. You can also have a snippet of code in a file and #include it everywhere you want.
Don't do this:
//forloop.txt
for(int i=0;i<SIZE;i++){
ARRAY[i] = VALUE;
}
//prime.txt
2147483647
//main.cpp
#include<iostream>
using std::cout;
using std::string;
int main(){
int prime =
#include "prime.txt"
;
int arr[10];
#define ARRAY arr
#define SIZE 10
#define VALUE prime
#include "forloop.txt"
#undef VALUE
#undef SIZE
#undef ARRAY
for(int i=10;i-- > 0;){
cout<<arr[i]<<'\n';
}
}
The using directive is not strictly needed. C++ has an idea of "namespaces" that prevents, for example, your max function to be considered different from the math function in cmath. It looks something like this:
namespace std{
int max(int i, int j){
if (i<j)
return j;
return i;
}
//some variable declaration and initialization
ostream cout(MAKE_BUFFER(stdout)); //std::ostream, if used outside
}
int max = 5;
int main(){
std::cout<<std::max(3,::max)<<'\n'; //::max refers to global name "max"
}
using namespace std; practically means "If you can't find a name globally, try sticking std:: in front and see if that's a name." People say it's bad practice to say using namespace std partly because if you #include "F.h", and F.h has using namespace std, then your code also uses namespace std (due to copy-paste #include).
Python is not a compiled language. When you say import X, you're giving a command to the interpreter to do something (run some code and make some name). #include is more like telling the compiler what to do to continue compiling at this point.
import in Python kind of means, "attach the names in this module". So import blah as x means, "Every variable (including functions) in blah can be accessed as x.THING". It also calls the module's initialization stuff, which makes sense, because the variables need to be initialized before you can use them.
Java is also a compiled language. In Java, the import statement doesn't play with files, it plays with classes. Every piece of code in Java has to belong to a class.
But unlike the other two languages, import is not strictly necessary. import is actually closer to C++'s using. import simply adds names for classes you can already use, except only to the current class.
Here's some code using imports.
import java.util.Scanner;
public class Example{
public static void main(String blargs[]){
Scanner cin = new Scanner(System.in);
System.out.println("Type in your name and press Enter: ");
System.out.println("Hello "+cin.next());
}
}
Here's the same program, using no imports.
public class Example{
public static void main(String blargs[]){
java.util.Scanner cin = new java.util.Scanner(System.in);
System.out.println("Type in your name and press Enter: ");
System.out.println("Hello "+cin.next());
}
}
Here's the same program, using all long names (import java.lang.*; is implicit in every Java source file).
public class Example{
public static void main(java.lang.String blargs[]){
java.util.Scanner cin = new java.util.Scanner(java.lang.System.in);
java.lang.System.out.println("Type in your name and press Enter: ");
java.lang.System.out.println("Hello "+cin.next());
}
}
Here's the same program, using all the imports.
import java.util.Scanner;
import static java.util.System.out;
import static java.util.System.in;
public class Example{
public static void main(String blargs[]){
Scanner cin = new Scanner(in);
out.println("Type in your name and press Enter: ");
out.println("Hello "+cin.next());
}
}

How to tell C++ to use a different function (with the same name as another function)?

I have two libraries included in my program which both have the same function name, but I need to be able to use both, but I also need C++ to know which one I'm referring to (in certain places I will only be referring to one or the other). The reason why I'm doing this is because I am making my own library and I want to have certain names for my functions, but they are conflicting with functions in someone else's library that I've included, and to make matters worse, some of my functions in my library actually USE the functions in the other persons library which has the same name.
My library is just a .h/.cpp file by the way. Also, when calling MY functions, I don't want any extra luggage such as myNameSpace::myFunc(). I just want to call it myFunc(). However, I don't mind calling the other persons function using a namespace (though I don't want to modify their library in case I break something). (I'm completely new to C++ btw)
HERES MY NEW (TEST - SO FAR) CODE : NOT WORKING W/ ERRORS:
error C2668: 'myFunc' : ambiguous call to overloaded function
main program.cpp
#include "otherslib.h"
#include "mylib.h"
#include <iostream>
using namespace myNamespace;
int main(){
std::cout << myFunc() << std::endl;
return 0;
}
mylib.h
#pragma once
namespace myNamespace{
int myFunc();
}
mylib.cpp
#include "mylib.h"
namespace myNamespace{
int myFunc(){
return 1;
}
}
otherslib.h
#pragma once
int myFunc();
otherslib.cpp
#include "otherslib.h"
int myFunc(){
return 0;
}
You should define your functions in a namespace, and use the namespace when calling them.
namespace myNamespace
{
int myFunc(etc) { ... }
}
int main() {
cout << myNamespace::myFunc();
}
To avoid having to specify your namespace all the time, you could do something like this:
namespace myNamespace
{
int myFunc(etc) { ... }
int main()
{
// Call your own myFunc:
myFunc();
// Call their myFunc:
::myFunc();
}
}