Commit 42816c0b authored by CHAMONT David's avatar CHAMONT David
Browse files

Work on C++20

parent b98ae015
# Programming styles
Topics more focused on the standard library, new best practices, and programming styles.
......@@ -21,4 +22,4 @@ Threads, synchronization, shared data, mutexes and locks, asynchronous calls.
---
© *CNRS 2022*
*This document was created by David Chamont. It is available under the [Licence Creative Commons - Attribution - No commercial use - Shared under the conditions 4.0 International](http://creativecommons.org/licenses/by-nc-sa/4.0/)*
*This document was created by David Chamont. It is available under the [Licence Creative Commons - Attribution - No commercial use - Shared under the conditions 4.0 International](http://creativecommons.org/licenses/by-nc-sa/4.0/)*
\ No newline at end of file
#include <iostream>
#include <vector>
template <class Itr1, class Itr2>
struct NodeBase
template <typename Itr1, typename Itr2>
struct ItrNodeBase
{
Itr1 itr1 ; Itr2 itr2 ;
NodeBase( Itr1 i1, Itr2 i2 ) : itr1(i1), itr2(i2) {}
ItrNodeBase( Itr1 i1, Itr2 i2 ) : itr1(i1), itr2(i2) {}
void operator ++() { ++itr1 ; ++itr2 ; }
} ;
template <class Itr1, class Itr2>
struct NodeAdd : public NodeBase<Itr1, Itr2>
template <typename Itr1, typename Itr2>
struct ItrNodeAdd : public ItrNodeBase<Itr1, Itr2>
{
using NodeBase<Itr1, Itr2>::NodeBase ;
using ItrNodeBase<Itr1, Itr2>::ItrNodeBase ;
double operator *() const
{ return (*(this->itr1))+(*(this->itr2)) ; }
} ;
template <class Itr1, class Itr2>
struct NodeSub : public NodeBase<Itr1, Itr2>
template <typename Itr1, typename Itr2>
struct ItrNodeSub : public ItrNodeBase<Itr1, Itr2>
{
using NodeBase<Itr1, Itr2>::NodeBase ;
using ItrNodeBase<Itr1, Itr2>::ItrNodeBase ;
double operator *() const
{ return (*(this->itr1))-(*(this->itr2)) ; }
} ;
......@@ -35,8 +35,8 @@ int main()
using int_itr = typename std::vector<int>::iterator ;
using double_itr = typename std::vector<double>::iterator ;
NodeAdd<int_itr, double_itr> node1{std::begin(array1),std::begin(array2)} ;
NodeSub<decltype(node1), double_itr> node2{node1,std::begin(array3)} ;
ItrNodeAdd<int_itr, double_itr> node1{std::begin(array1),std::begin(array2)} ;
ItrNodeSub<decltype(node1), double_itr> node2{node1,std::begin(array3)} ;
for ( int i = 0 ; i<size ; ++i )
{ std::cout<<(*node2)<<std::endl ; ++node2 ; }
......
......@@ -6,8 +6,8 @@ struct Vector
{
double data[3] ;
template <typename Node>
void operator=( Node && node )
template <typename ItrNode>
void operator=( ItrNode && node )
{
data[0] = *node ; ++node ;
data[1] = *node ; ++node ;
......@@ -20,61 +20,61 @@ std::ostream & operator<<( std::ostream & os, Vector const & v )
// Nodes
template <class Itr1, class Itr2>
struct NodeBase
template <typename Itr1, typename Itr2>
struct ItrNodeBase
{
Itr1 itr1 ; Itr2 itr2 ;
NodeBase( Itr1 i1, Itr2 i2 ) : itr1(i1), itr2(i2) {}
ItrNodeBase( Itr1 i1, Itr2 i2 ) : itr1(i1), itr2(i2) {}
void operator ++() { ++itr1 ; ++itr2 ; }
} ;
template <class Itr1, class Itr2>
struct NodeAdd : public NodeBase<Itr1, Itr2>
template <typename Itr1, typename Itr2>
struct ItrNodeAdd : public ItrNodeBase<Itr1, Itr2>
{
using NodeBase<Itr1, Itr2>::NodeBase ;
using ItrNodeBase<Itr1, Itr2>::ItrNodeBase ;
double operator *() const
{ return (*(this->itr1))+(*(this->itr2)) ; }
} ;
template <class Itr1, class Itr2>
struct NodeSub : public NodeBase<Itr1, Itr2>
template <typename Itr1, typename Itr2>
struct ItrNodeSub : public ItrNodeBase<Itr1, Itr2>
{
using NodeBase<Itr1, Itr2>::NodeBase ;
using ItrNodeBase<Itr1, Itr2>::ItrNodeBase ;
double operator *() const
{ return (*(this->itr1))-(*(this->itr2)) ; }
} ;
// Operators
template <class Node1, class Node2>
auto operator +( const Node1 & n1, const Node2 & n2 )
{ return NodeAdd<Node1,Node2>{n1,n2} ; }
template <typename ItrNode1, typename ItrNode2>
auto operator +( const ItrNode1 & n1, const ItrNode2 & n2 )
{ return ItrNodeAdd<ItrNode1,ItrNode2>{n1,n2} ; }
template <class Node>
auto operator +( Vector const & v, Node const & n )
{ return NodeAdd<double const *,Node>{v.data,n} ; }
template <typename ItrNode>
auto operator +( Vector const & v, ItrNode const & n )
{ return ItrNodeAdd<double const *,ItrNode>{v.data,n} ; }
template <class Node>
auto operator +( Node const & n, Vector const & v )
{ return NodeAdd<Node,double const *>{n,v.data} ; }
template <typename ItrNode>
auto operator +( ItrNode const & n, Vector const & v )
{ return ItrNodeAdd<ItrNode,double const *>{n,v.data} ; }
auto operator +( Vector const & v1, Vector const & v2 )
{ return NodeAdd<double const *,double const *>{v1.data,v2.data} ; }
{ return ItrNodeAdd<double const *,double const *>{v1.data,v2.data} ; }
template <class Node1, class Node2>
auto operator -( const Node1 & n1, const Node2 & n2 )
{ return NodeSub<Node1,Node2>{n1,n2} ; }
template <typename ItrNode1, typename ItrNode2>
auto operator -( const ItrNode1 & n1, const ItrNode2 & n2 )
{ return ItrNodeSub<ItrNode1,ItrNode2>{n1,n2} ; }
template <class Node>
auto operator -( Vector const & v, Node const & n )
{ return NodeSub<double const *,Node>{v.data,n} ; }
template <typename ItrNode>
auto operator -( Vector const & v, ItrNode const & n )
{ return ItrNodeSub<double const *,ItrNode>{v.data,n} ; }
template <class Node>
auto operator -( Node const & n, Vector const & v )
{ return NodeSub<Node,double const *>{n,v.data} ; }
template <typename ItrNode>
auto operator -( ItrNode const & n, Vector const & v )
{ return ItrNodeSub<ItrNode,double const *>{n,v.data} ; }
auto operator -( Vector const & v1, Vector const & v2 )
{ return NodeSub<double const *,double const *>{v1.data,v2.data} ; }
{ return ItrNodeSub<double const *,double const *>{v1.data,v2.data} ; }
// Main
......
......@@ -8,7 +8,7 @@
}
},
"source": [
"# A glimpse of C++20\n",
"# A glimpse to C++20\n",
"\n",
"The new standard is full of multiple items, small or big. Let's focus on what Rainer Grimm calls \"The Big Four\", which will drive us to the \"post-modern\" C++.\n",
"1. for what concerns compilation: [**modules**](en.1-modules.ipynb) ;\n",
......@@ -61,18 +61,23 @@
"metadata": {
"celltoolbar": "Diaporama",
"kernelspec": {
"display_name": "C++17",
"language": "C++17",
"name": "xcpp17"
"display_name": "Python 3 (ipykernel)",
"language": "python",
"name": "python3"
},
"language_info": {
"codemirror_mode": "text/x-c++src",
"file_extension": ".cpp",
"mimetype": "text/x-c++src",
"name": "c++",
"version": "17"
"codemirror_mode": {
"name": "ipython",
"version": 3
},
"file_extension": ".py",
"mimetype": "text/x-python",
"name": "python",
"nbconvert_exporter": "python",
"pygments_lexer": "ipython3",
"version": "3.9.5"
}
},
"nbformat": 4,
"nbformat_minor": 4
}
\ No newline at end of file
}
......@@ -144,7 +144,7 @@
}
},
"source": [
"We can now **easily import modules**, as in any recent languages. If the standard library was written as a single module (this is not yet achieved), one may write:"
"One can now **easily import modules**, as in any recent languages. If the standard library was written as a single module (this is not yet achieved), one may write:"
]
},
{
......@@ -171,7 +171,7 @@
}
},
"source": [
"### Defining a module"
"### Defining a module... the terminology"
]
},
{
......@@ -204,7 +204,7 @@
}
},
"source": [
"A typical setup, for each individual module, would be to have a header-like file, called **Primary Module Interface Unit**), and a body-like file, called a **Module Implementation Unit**. "
"A typical setup, for each individual module, would be to have a *header-like* file, called **primary module interface unit**, and a *body-like* file, called a **module implementation unit**. "
]
},
{
......@@ -215,7 +215,7 @@
}
},
"source": [
"If one want to divide the module even more, he can subdivide the units into **Module Interface Partitions** and **Module Implementation Partitions**."
"If one want to divide the module even more, he can subdivide the units into **module interface partitions** and **module implementation partitions**."
]
},
{
......@@ -237,7 +237,7 @@
}
},
"source": [
"To be noticed: some module units are kind of header/interface files, yet they now need to be compiled !"
"**To be noticed**: some module units are kind of header/interface files, yet they now need to be compiled !"
]
},
{
......@@ -248,7 +248,9 @@
}
},
"source": [
"### Diversity of strategies and implementations"
"### Diversity of strategies and implementations\n",
"\n",
"> there is no one way of correctly using C++20 modules\". *[Niall Cooling](https://blog.feabhas.com/2021/08/c20-modules-with-gcc11/)*"
]
},
{
......@@ -259,7 +261,7 @@
}
},
"source": [
"As stated by [Niall Cooling](https://blog.feabhas.com/2021/08/c20-modules-with-gcc11/): \"there is no one way of correctly using C++20 modules\". In the following examples, we will stick to the usual interface+implementation pair of files for each module, similar to the old-school header+body files. This is somehow a modern implementation of the old \"precompiled header files\"."
"The C++20 standard does not enforce a single way to split the modules into files, the file suffix, the use of auxiliary directories/files... the implementation of **C++ modules may differ significantly between compilers**."
]
},
{
......@@ -270,7 +272,7 @@
}
},
"source": [
"The C++20 standard does not enforce a single way to split the modules into files, the file suffix, the use of auxiliary directories/files... the implementation of **C++ modules may differ significantly between compilers**. In the following examples, we will investigate the GCC implementation."
"In the following examples, we will investigate the GCC implementation, and we will stick to the usual *interface+implementation* pair of files for each module, similar to the old-school *header+body* files. This is somehow a modern implementation of the old \"precompiled header files\"."
]
},
{
......@@ -288,16 +290,38 @@
"cell_type": "markdown",
"metadata": {
"slideshow": {
"slide_type": "skip"
"slide_type": "fragment"
}
},
"source": [
"GCC does not introduce some new files extensions, it is up to you to define some convention. Let's use a *pre-suffix* **`_mh`** for a header-like file (*Primary Module Interface Unit*), and **`_mb`** for a body-like file (*Module Implementation Unit*)."
]
},
{
"cell_type": "markdown",
"metadata": {
"slideshow": {
"slide_type": "fragment"
}
},
"source": [
"GCC requires the options **`-std=c++20 -fmodules-ts`**, and will produce an object file for each module file."
]
},
{
"cell_type": "markdown",
"metadata": {
"slideshow": {
"slide_type": "fragment"
}
},
"source": [
"GCC does not introduce some new file extension, it is up to you to define some convention for the name files. Here we will use a \"pre-suffix\" `_mh` a header-like file, called **Primary Module Interface Unit**), and `_mb` for a body-like file, called a **Module Implementation Unit**. GCC requires the options `-std=c++20 -fmodules-ts`, and will produce an object file for each module file. Warning: GCC requires the module inerface to be compiled before the moduel implementation."
"Warning: GCC requires the module interface to be compiled before the module implementation."
]
},
{
"cell_type": "code",
"execution_count": 87,
"execution_count": 8,
"metadata": {
"slideshow": {
"slide_type": "subslide"
......@@ -333,7 +357,7 @@
},
{
"cell_type": "code",
"execution_count": 88,
"execution_count": 9,
"metadata": {
"slideshow": {
"slide_type": "fragment"
......@@ -346,7 +370,7 @@
},
{
"cell_type": "code",
"execution_count": 89,
"execution_count": 10,
"metadata": {
"slideshow": {
"slide_type": "subslide"
......@@ -372,7 +396,7 @@
},
{
"cell_type": "code",
"execution_count": 90,
"execution_count": 11,
"metadata": {
"slideshow": {
"slide_type": "fragment"
......@@ -385,7 +409,7 @@
},
{
"cell_type": "code",
"execution_count": 93,
"execution_count": 12,
"metadata": {
"slideshow": {
"slide_type": "subslide"
......@@ -413,7 +437,7 @@
},
{
"cell_type": "code",
"execution_count": 94,
"execution_count": 13,
"metadata": {
"slideshow": {
"slide_type": "fragment"
......@@ -426,7 +450,7 @@
},
{
"cell_type": "code",
"execution_count": 95,
"execution_count": 14,
"metadata": {
"slideshow": {
"slide_type": "fragment"
......@@ -460,7 +484,7 @@
},
{
"cell_type": "code",
"execution_count": 78,
"execution_count": 17,
"metadata": {
"slideshow": {
"slide_type": "subslide"
......@@ -471,7 +495,7 @@
"name": "stdout",
"output_type": "stream",
"text": [
"Overwriting tmp.answer_mh.cc\n"
"Writing tmp.answer_mh.cc\n"
]
}
],
......@@ -488,7 +512,7 @@
},
{
"cell_type": "code",
"execution_count": 79,
"execution_count": 18,
"metadata": {
"slideshow": {
"slide_type": "fragment"
......@@ -501,7 +525,7 @@
},
{
"cell_type": "code",
"execution_count": 80,
"execution_count": 19,
"metadata": {
"slideshow": {
"slide_type": "subslide"
......@@ -533,7 +557,7 @@
},
{
"cell_type": "code",
"execution_count": 81,
"execution_count": 20,
"metadata": {
"slideshow": {
"slide_type": "fragment"
......@@ -546,7 +570,7 @@
},
{
"cell_type": "code",
"execution_count": 84,
"execution_count": 21,
"metadata": {
"slideshow": {
"slide_type": "subslide"
......@@ -557,7 +581,7 @@
"name": "stdout",
"output_type": "stream",
"text": [
"Overwriting tmp.main2.cpp\n"
"Writing tmp.main2.cpp\n"
]
}
],
......@@ -575,7 +599,7 @@
},
{
"cell_type": "code",
"execution_count": 85,
"execution_count": 22,
"metadata": {
"slideshow": {
"slide_type": "fragment"
......@@ -588,7 +612,7 @@
},
{
"cell_type": "code",
"execution_count": 86,
"execution_count": 23,
"metadata": {
"slideshow": {
"slide_type": "fragment"
......@@ -622,7 +646,7 @@
},
{
"cell_type": "code",
"execution_count": 57,
"execution_count": 24,
"metadata": {
"slideshow": {
"slide_type": "subslide"
......@@ -651,7 +675,7 @@
},
{
"cell_type": "code",
"execution_count": 58,
"execution_count": 25,
"metadata": {
"slideshow": {
"slide_type": "fragment"
......@@ -664,7 +688,7 @@
},
{
"cell_type": "code",
"execution_count": 59,
"execution_count": 26,
"metadata": {
"slideshow": {
"slide_type": "subslide"
......@@ -694,7 +718,7 @@
},
{
"cell_type": "code",
"execution_count": 60,
"execution_count": 27,
"metadata": {
"slideshow": {
"slide_type": "fragment"
......@@ -707,7 +731,7 @@
},
{
"cell_type": "code",
"execution_count": 61,
"execution_count": 28,
"metadata": {
"slideshow": {
"slide_type": "subslide"
......@@ -735,7 +759,7 @@
},
{
"cell_type": "code",
"execution_count": 62,
"execution_count": 29,
"metadata": {
"slideshow": {
"slide_type": "fragment"
......@@ -748,7 +772,7 @@
},
{
"cell_type": "code",
"execution_count": 63,
"execution_count": 30,
"metadata": {
"slideshow": {
"slide_type": "fragment"
......@@ -767,6 +791,19 @@
"!./tmp.main3.exe"
]
},
{
"cell_type": "code",
"execution_count": 25,
"metadata": {
"slideshow": {
"slide_type": "fragment"
}
},
"outputs": [],
"source": [
"!rm -f tmp.math_mh.o && g++ -c -std=c++20 -fmodules-ts tmp.math_mh.cc -o tmp.math_mh.o"
]
},
{
"cell_type": "markdown",
"metadata": {
......@@ -775,7 +812,112 @@
}
},
"source": [
"## What about templates ?"
"## What about templates ?\n",
"\n",
"It sounds like, as before, one must put the template body in the module interface."
]
},
{
"cell_type": "code",
"execution_count": 49,
"metadata": {
"slideshow": {
"slide_type": "subslide"
}
},
"outputs": [
{
"name": "stdout",
"output_type": "stream",
"text": [
"Overwriting tmp.math_mh.cc\n"
]
}
],
"source": [
"%%file tmp.math_mh.cc\n",
"\n",
"export module math ;\n",
"\n",
"export\n",
"template< typename T >\n",
"T add( T first, T second )\n",
" { return first + second ; } "
]
},
{
"cell_type": "code",
"execution_count": 50,
"metadata": {
"slideshow": {
"slide_type": "fragment"
}
},
"outputs": [],
"source": [
"!rm -f tmp.math_mh.o && g++ -c -std=c++20 -fmodules-ts tmp.math_mh.cc -o tmp.math_mh.o"
]
},
{
"cell_type": "code",
"execution_count": 51,
"metadata": {
"slideshow": {
"slide_type": "subslide"
}
},
"outputs": [
{
"name": "stdout",
"output_type": "stream",
"text": [
"Overwriting tmp.main3.cpp\n"
]
}
],
"source": [
"%%file tmp.main3.cpp\n",
"\n",
"#include <iostream>\n",
"\n",
"import math ;\n",
"\n",
"int main()\n",
" { std::cout<<add(40, 2)<<std::endl ; }"
]
},
{
"cell_type": "code",
"execution_count": 52,
"metadata": {
"slideshow": {
"slide_type": "fragment"
}
},
"outputs": [],
"source": [
"!rm -f tmp.main3.exe && g++ -std=c++20 -fmodules-ts tmp.main3.cpp -o tmp.main3.exe tmp.math_mh.o"
]
},
{
"cell_type": "code",
"execution_count": 53,
"metadata": {
"slideshow": {
"slide_type": "fragment"
}