C++17 – Italian C++ Community https://www.italiancpp.org Mon, 24 Aug 2020 13:03:53 +0000 it-IT hourly 1 https://wordpress.org/?v=4.7.18 106700034 Meetup Giugno / Modena https://www.italiancpp.org/event/meetup-giugno2018/ Thu, 14 Jun 2018 18:00:00 +0000 http://www.italiancpp.org/?post_type=tribe_events&p=8620

Post-modern C++ Refactoring

Facilitatore: Marco Arena

Un nuovo appuntamento a Modena dedicato al C++ organizzato in collaborazione con l’associazione ConoscereLinux.

 

Ultima serata prima della pausa estiva (Luglio e Agosto).
Faremo un workshop per imparare sul campo idiomi e costrutti del C++ di “nuova generazione”.
Facilitatore: Marco Arena.

20:00

Arrivo e saluti iniziali – Marco Arena

20:05

Workshop: Post-modern C++ refactoring – Marco Arena

Bruce Lee affermava che “il miglior combattente non è un pugile un karateka o un judoka, ma colui che sa adattarsi a qualsiasi stile”. Ho sempre associato questa idea al C++ perché flessibile e indipendente da un paradigma particolare.

Questa convinzione si è rafforzata notevolmente nell’ultima decade: con 3 aggiornamenti dello standard il C++ e il suo ecosistema hanno accolto costrutti e idiomi provenienti da paradigmi differenti.

I programmatori C++ di nuova generazione devono conoscere e, spesso, padroneggiare più di un paradigma, non solo per essere capaci di manutenere efficacemente codice “misto” ma anche per gestire al meglio situazioni dove un certo paradigma prevale sugli altri (“no size fits all”).

In questo workshop impareremo e ci eserciteremo su alcuni degli idiomi e concetti più importanti del C++ nel 2018, passando per gli ultimi 3 standard.

Useremo tech.io, una piattaforma interattiva, facendo brevi esercizi di refactoring su una piccola codebase pseudo-legacy. I PC li forniamo noi.

FAQ

1) Sono uno studente/principiante e conosco poco il C++. Posso partecipare?
Assolutamente sì! Ogni sezione sarà introdotta da un po’ di teoria e gli esercizi saranno semplici.
E ovviamente puoi fare domande!

2) Il codice sarà disponibile dopo il workshop?
Assolutamente sì! La piattaforma resta attiva anche dopo il workshop e, inoltre, potrai compilare tutto in locale perché il progetto sarà su github (con un CMake già pronto).

3) Sono un esperto programmatore C++. Mi annoierò?
Eh ma se parti così… 🙂 Proverò a sorprenderti con qualche idioma nascosto che magari ti sei perso. Oppure potrai aggiungere tu più valore al workshop condividendo qualcosa.

22:00

Pizza e networking

 

Materiale della serata:


Come sono strutturati i nostri meetup serali:

  • presentazione tecnica con formato a scelta dello speaker (talk frontale, workshop, live coding, ecc)
  • spazio fare domande e confrontarsi
  • una pizza tutti insieme per fare networking e, perché no, parlare d’altro

In regalo a tutti i partecipanti i nostri mitici stickers 🙂

]]>
8620
Mini-Meetup Serale / Bologna https://www.italiancpp.org/event/meetup-marzo2017/ Tue, 21 Mar 2017 18:00:00 +0000 http://www.italiancpp.org/?post_type=tribe_events&p=7401

L’Italian C++ Community ha co-organizzato con l’XPUG di Bologna un mini-meetup serale, con l’obiettivo aprire un dialogo sullo sviluppo C++ nel Bolognese.

Speaker e moderatore dell’evento: Marco Arena, fondatore e presidente della community. Le novità del C++17 “for the daily job” hanno costituito la traccia della serata, completamente guidata da esempi lanciati sulle ultime versioni dei maggiori compilatori esistenti – GCC, Visual Studio 2017, Clang – per capire anche chi supporta cosa.

La serata ha voluto essere soprattutto un momento di incontro, per conoscersi, discutere, interagire. Tutti si sono presentati, hanno fatto osservazioni e domande.

Il meetup si è concluso con una pizza in compagnia.

 

]]>
7401
Mini-Meetup Serale / Modena https://www.italiancpp.org/event/meetup-febbraio2017/ Wed, 22 Feb 2017 19:00:00 +0000 http://www.italiancpp.org/?post_type=tribe_events&p=7413

Marco Arena, fondatore e presidente dell’Italian C++ Community nonché assiduo moderatore di Coding Dojo, ha presentato le novità del C++17 “for the daily job”, mostrando esempi sulle ultime versioni dei maggiori compilatori esistenti – GCC, Visual Studio 2017, Clang – per capire chi supporta cosa.

La serata si è trasformata in una discussione interattiva, un momento di incontro, tra le persone interessate la C++ nel Modenese. 16 partecipanti.

Il meetup si è concluso in pizzeria con chi è potuto rimanere.

 

 

]]>
7413
Coroutines Internals https://www.italiancpp.org/2016/11/02/coroutines-internals/ Wed, 02 Nov 2016 09:15:30 +0000 http://www.italiancpp.org/?p=6862 Article's code is available on Github

What are coroutines and why should I care?

In The Art of Computer Programming Donald Knuth introduced coroutines as an alternative to the usual function caller/callee idiom where two pieces of code were treated as cooperating equals.
Coroutines can be thought of as language-level constructs that generalize subroutines by providing multiple exit/entry points. A normal subroutine usually has a starting point and one or more exit (return) points. A coroutine provides the ability to enter/exit its control flow at different spots therefore allowing for greater code expressiveness, preservation of automatic states across function calls and nonpreemptive multitasking.

It has to be noted that different programming languages can provide various levels of support for coroutines, e.g.

  • Languages supporting the yield keyword
  • Languages providing full support for async, await, yield

In this article we’ll focus on the former.

Thoughtful use of coroutines can lead to cleaner and more maintainable code in a variety of situations. As a motivating example let’s take for instance the following pseudocode

function start_accepting() {

  socket.async_accept(accept_handler);

  start_accepting();

}

function accept_handler() {

  socket.async_read(read_handler);
 
}

function read_handler(data) {

  request = parse_data(data);

  switch(request) {

    case SEND_DATA: {

      data_to_send = prepare_data_for(request);

      socket.async_write(data_to_send, write_handler);

    } break;

  };

}

function write_handler() {

  ... // continue execution

}

Asynchronous programming is often the preferred way of accomplishing potentially blocking operations without stalling the thread on blocking calls. In the pseudocode above we’re assuming (and omitting for clarity’s sake) that all operations are queued and handled by an event loop manager (a common and powerful idiom in asynchronous applications programming, cfr. boost::asio).

Coroutines allow modeling the same behavior with more readable code

coroutine acceptor() {

  while(true) {

    socket.async_accept_connection(yield); // To event manager

    start_coroutine(serve_request);

  }

}

coroutine serve_request() {

  socket.async_read(data, yield);

  request = parse_data(data);

  switch(request) {

    case SEND_DATA: {

      data_to_send = prepare_data_for(request);

      socket.async_write(data_to_send, yield);

      ... // Continue execution

    } break;

  };

}

 

The code in serve_request() uses a sequential-looking paradigm

Coroutines let you create a structure that mirrors the actual program logic. Asynchronous operations don’t split functions, because there are no handlers to define what should happen when an asynchronous operation completes. Instead of having handlers call each other, the program can use a sequential structure.

(boost.asio-coroutines)

 

Standard support

At the time of writing this article coroutines didn’t make it for the next standard version (C++17) although recent MSVC versions already ship with an /await option to test experimental support for coroutines.

Coroutines internals

It is important to understand the role of coroutines in providing a collaborative non-preemptive multitasking: spawning a coroutine does not spawn a new thread of execution but coroutines waive execution by yielding to callers (asymmetric coroutines) or to other coroutines (symmetric coroutines) explicitly.

Since coroutines are concepts that have been known for a relatively long time many different techniques (both at language level and system level) have been devised (an interesting suggested reading: Duff’s device based coroutines).

Implementing basic support for asymmetric stackful coroutines can be a rewarding experience in terms of understanding the relationship between coroutines and the way these program flow constructs interact with callers and the underlying memory. Most of the code that will be presented is a pruned-down version of the coroutine implementation by Oliver Kowalke (cfr. boost::coroutine2) available with the boost libraries.

Abstracting away the execution context

In order to implement a coroutine context switch (in its simplest form from the callee to the caller) we need a mechanism to abstract the execution state of our routines and to save/restore stack, registers, CPU flags, etc.

A context switch between threads on x86_64 can be quite costly in terms of performances since it also involves a trip to kernel syscalls. Coroutines context switches in the same thread are far more lightweight and require no kernel interaction. The foundation bricks for userland context switches are contained in the boost/context library. These functionalities provide a solid abstraction that can provide ready-to-use stacks (either basic malloc’d stack buffers or even split stacks on supported architectures) to store our context data or complement system-level constructs (e.g. ucontext on Unix systems, Fibers on Windows). It has to be noted that boost::context used to support Windows fibers due to undocumented TEB-swapping related issues; after fixes were deployed support was dropped since the introduction of execution context v2.

In this article we’ll go for a fcontext implementation in assembler on a x86_64 Unix system (no system calls involved).

Saving the state

When a coroutine yields an fcontext switch should occur, i.e. we should save whatever state the routine was at that point in time and JMP to another context. On a recent Unix system calling conventions, object and executable file formats and other low-level ABI issues are defined by the System V ABI. On a x86_64 architecture the stack grows downwards and parameters to functions are passed in registers rdi, rsi, rcx, r8, r9 + additional stack space if needed. The stack is always 16-byte aligned before a call instruction is issued. Registers rbx, rsp, rbp, r12, r13, r14, and r15 are preserved across function calls while rax, rdi, rsi, rdx, rcx, r8, r9, r10, r11 are scratch registers:

Return value Parameter Registers Scratch Registers Preserved Registers
rax, rdx rdi, rsi, rdx, rcx, r8, r9 + additional_stack rax, rdi, rsi, rdx, rcx, r8, r9, r10, r11 rbx, rsp, rbp, r12, r13, r14, r15

Therefore following in boost::context‘s footsteps a reasonable memory layout is the following

/****************************************************************************************
 *                                                                                      *
 *  ----------------------------------------------------------------------------------  *
 *  |    0    |    1    |    2    |    3    |    4     |    5    |    6    |    7    |  *
 *  ----------------------------------------------------------------------------------  *
 *  |   0x0   |   0x4   |   0x8   |   0xc   |   0x10   |   0x14  |   0x18  |   0x1c  |  *
 *  ----------------------------------------------------------------------------------  *
 *  |        R12        |         R13       |         R14        |        R15        |  *
 *  ----------------------------------------------------------------------------------  *
 *  ----------------------------------------------------------------------------------  *
 *  |    8    |    9    |   10    |   11    |    12    |    13   |    14   |    15   |  *
 *  ----------------------------------------------------------------------------------  *
 *  |   0x20  |   0x24  |   0x28  |  0x2c   |   0x30   |   0x34  |   0x38  |   0x3c  |  *
 *  ----------------------------------------------------------------------------------  *
 *  |        RBX        |         RBP       |         RIP        |       EXIT        |  *
 *  ----------------------------------------------------------------------------------  *
 *                                                                                      *
 ****************************************************************************************/

The EXIT field is going to be left unused for our purposes but it will be left in place anyway.

The first thing we need is to allocate space to store the context data and make sure it has a valid alignment for the architecture we’re dealing with

// Allocate context-stack space
context_stack = (void*)malloc(64_Kb);

std::size_t space = UNIX_CONTEXT_DATA_SIZE + 64;
sp = static_cast<char*>(context_stack) + 64_Kb - space;

sp = std::align(64, UNIX_CONTEXT_DATA_SIZE, sp, space);
assert(sp != nullptr && space >= UNIX_CONTEXT_DATA_SIZE);

boost::context offers both memory-efficient on-demand growing stacks or fixed stack allocations (cfr. boost docs). In this example code we’ll go for a fixed stack allocation.
Since we can’t deal with registers directly in C++ we’ll have to fallback on a pure assembly routine. The GAS backend seems the logical tool of choice for this work. We therefore define an external function to link against our executable with C linkage:

extern "C" fcontext_t jump_to_context(fcontext_t context);

What is an fcontext_t? In a x86_64 world it is just a register’s content:

using fcontext_t = void*;

Luckily for us RIP will have already been set by the fact we’re invoking jump_to_context with a CALL instruction so we get an instruction pointer on the stack for free in our assembly code:

.text
.globl jump_to_context
.type jump_to_context,@function
.align 16
jump_to_context:
    pushq  %rbp  /* save RBP */
    pushq  %rbx  /* save RBX */
    pushq  %r15  /* save R15 */
    pushq  %r14  /* save R14 */
    pushq  %r13  /* save R13 */
    pushq  %r12  /* save R12 */

    /* omissis */

    /* restore RSP (pointing to context-data) from RDI */
    movq  %rdi, %rsp

    popq  %r12  /* restore R12 */
    popq  %r13  /* restore R13 */
    popq  %r14  /* restore R14 */
    popq  %r15  /* restore R15 */
    popq  %rbx  /* restore RBX */
    popq  %rbp  /* restore RBP */

    /* continue... */

.size jump_to_context,.-jump_to_context

/* Mark that we don't need executable stack. */
.section .note.GNU-stack,"",%progbits

Using CMake putting everything together becomes quite easy:

project(simple_crts CXX ASM)
cmake_minimum_required(VERSION 2.8.12)
set (CMAKE_CXX_STANDARD 14)

set_source_files_properties(jump_to_context_x86_64_elf_gas.S 
                            PROPERTIES COMPILE_FLAGS "-x assembler-with-cpp")

add_executable(simple_crts simple_crts.cpp jump_to_context_x86_64_elf_gas.S)
target_link_libraries(simple_crts ${CONAN_LIBS} pthread)

Trampolines to coroutines

Something is missing at this point: we need a valid RIP pointer to the coroutine to jump to. We could enter the coroutine and have another function store this information for us, but there’s a better way which avoids cluttering the coroutine code entirely: using a trampoline function.

Just as in boost::context, we define a trampoline function ourselves which, when jumped to, re-jumps to the caller and saves its context as a pre-stage for the coroutine:

void trampoline(fcontext_t ctx) {

  yield_ctx = jump_to_context(ctx);

  wannabe_coroutine();
}

What we have to do now is a simplified version of the make_context routine to set the first RIP towards the trampoline’s prologue:

// Do make_context's work (simplified)
// Do *NOT* try this at home (or even worse in the office)
void** addr = reinterpret_cast<void**>(static_cast<char*>(sp) +
                                         UNIX_CONTEXT_DATA_RIP_OFFSET);
*addr = reinterpret_cast<void*>(&trampoline);

// In a more complex case there might be additional initialization and
// frame adjustments going on
coroutine_ctx = jump_to_context(sp);

So right now we have a valid trampoline RIP set in place:

/****************************************************************************************
 *                                                                                      *
 *  ----------------------------------------------------------------------------------  *
 *  |    0    |    1    |    2    |    3    |    4     |    5    |    6    |    7    |  *
 *  ----------------------------------------------------------------------------------  *
 *  |   0x0   |   0x4   |   0x8   |   0xc   |   0x10   |   0x14  |   0x18  |   0x1c  |  *
 *  ----------------------------------------------------------------------------------  *
 *  |        R12        |         R13       |         R14        |        R15        |  *
 *  ----------------------------------------------------------------------------------  *
 *  ----------------------------------------------------------------------------------  *
 *  |    8    |    9    |   10    |   11    |    12    |    13   |    14   |    15   |  *
 *  ----------------------------------------------------------------------------------  *
 *  |   0x20  |   0x24  |   0x28  |  0x2c   |   0x30   |   0x34  |   0x38  |   0x3c  |  *
 *  ----------------------------------------------------------------------------------  *
 *  |        RBX        |         RBP       |         RIP        |       EXIT        |  *
 *  ----------------------------------------------------------------------------------  *
 *                                           ^^^^^^^^^^^^^^^^^^^^                       *
 ****************************************************************************************/

This kickstarts the bouncing to/from the trampoline:

.text
.globl jump_to_context
.type jump_to_context,@function
.align 16
jump_to_context:
    pushq  %rbp
    pushq  %rbx 
    pushq  %r15 
    pushq  %r14 
    pushq  %r13 
    pushq  %r12 

    /* store RSP (pointing to context-data) in RAX */
    movq  %rsp, %rax

    movq  %rdi, %rsp

    popq  %r12 
    popq  %r13 
    popq  %r14 
    popq  %r15 
    popq  %rbx 
    popq  %rbp 

    /* restore return-address (must have been put on the new stack) */
    popq  %r8

    /*
       pass the old context as first parameter (if we're headed
       towards a landing function)
    */
    movq  %rax, %rdi

    /* indirect jump to new context */
    jmp  *%r8

.size jump_to_context,.-jump_to_context
.section .note.GNU-stack,"",%progbits

It is important to note that we’re keeping the stack aligned during this entire process (recall that the stack has to be 16-bytes aligned before a call instruction is issued).

The process roughly goes on like this:
coroutines_graph1

It has to be noted that the trampoline function might reserve stack space for its parameters as well. In the code above we allocated 64Kb of heap space to be used as stack space for context operations. So after the first jump the sp automatic variable is no longer reliable. coroutine_ctx should be used instead.

Resuming fcontext

Resuming trampoline’s fcontext requires another call and rip-save and stack pointer adjustment to coroutine_ctx. Trampoline’s old RIP will be available for free after we’ve restored the first 48 bytes of the fcontext.

Execution can afterwards continue to the designated coroutine. At this point the coroutine should be somehow encapsulated to be able to use the yield_ctx context pointer: that is the gateway to our (in an asymmetric view) caller context.

Each time we want to yield execution back to the caller we’ll have to jump_to_context to the yield_ctx:

void yield() {
  yield_ctx = jump_to_context(yield_ctx);
}

void wannabe_coroutine() {
  std::cout << "I wanna be a coroutine when I grow my stack space up\n";
  yield();
  std::cout << "Hooray!\n";
  yield();
}

Notice that we’re also reassigning the variable with the return value provided by jump_to_context. This assignment is not executed until the control flow comes back to the yield() function:

.. save

/* store RSP (pointing to context-data) in RAX */
movq  %rsp, %rax

.. restore

This is a cooperative behavior example: each jump_to_context() invocation from this point onward actually returns fcontext data for the previous invocation.

The rest of the code bounces back and forth through the contexts resulting in the following sequence:

coroutines_graph2

At the end of the day the stack is freed (sounds weird to say) and the program terminates.

Exercise: wrapping up

As a didactic exercise (i.e. do not EVER use this code in a production environment) we can use some metaprogramming to wrap our coroutines and avoid polluting our code with stack adjustments and cleanup boilerplate. Eventually we’d like to end up with code like this

int g_fib = -1;

void fibonacci_gen() {

  int first = 1;
  g_fib = first;
  yield();

  int second = 1;
  g_fib = second;
  yield();

  for (int i = 0; i < 9; ++i) {

    int third = first + second;
    first = second;
    second = third;
    g_fib = third;
    yield();

  }

}

int main() {

  // Outputs the first 10 Fibonacci numbers

  coroutine<void(void)> coro(fibonacci_gen);

  for (int i = 0; i <= 10; ++i) {
      coro.resume();

    if(i) std::cout << g_fib << " ";
  }

}

To do this we create a templated wrapper class:

template class coroutine;

that will handle the stack and trampoline setup for us. One difference from the first example is the need for a wrapper that will handle the trampoline invocation (shields us from implementation-dependent issues):

template 
void call_member_trampoline(coroutine *instance, fcontext_t ctx) {
  instance->trampoline(ctx);
}

The trampoline is therefore modified as follows:

void trampoline(fcontext_t ctx) {

  size_t index = yield_ctx.size() - 1;
  yield_ctx[index] = jump_to_context(this, ctx);

  this->m_fn();
}

The only difference in the jump_to_context() function is in handling its new arity:

/* restore RSP (pointing to context-data) from RSI */
movq  %rsi, %rsp

and the promotion of %rdi from scratch-register to parameter-register (since we’re directly jumping to a destination context’s RIP).

The rest of the code remains largely unchanged.

Back to boost::context

If you’ve followed through the entire article and you made it here, you should by now know what the following boost::context2 program does:

#include <boost/context/all.hpp>
#include <iostream>
#include <array>

namespace ctx = boost::context::detail;

class Coroutine {
public:
  Coroutine() {
    my_context = ctx::make_fcontext(
      stack.data() + stack.size(),
      stack.size(),
      &Coroutine::dispatch
    );
  }
  virtual ~Coroutine() {}

  void operator()() {
    auto transfer_ctx = ctx::jump_fcontext(my_context, this);
    my_context = transfer_ctx.fctx;
  }

protected:
  void yield() {
    auto transfer_ctx = ctx::jump_fcontext(yield_context, 0);
    my_context = transfer_ctx.fctx;
  }

  virtual void call() = 0;

private:
  static void dispatch(ctx::transfer_t coroutine_ptr) {
    Coroutine *coroutine = reinterpret_cast<Coroutine *>(coroutine_ptr.data);
    coroutine->yield_context = coroutine_ptr.fctx;
    coroutine->call();
    while(true)
      coroutine->yield();
  }

private:
  ctx::fcontext_t my_context;
  ctx::fcontext_t yield_context;
  std::array<intptr_t, 66 * 1024> stack;
};

struct A : public Coroutine {
  void call() {
    std::cout << " __________________________________ " << std::endl;
    yield();
    std::cout << "|    _       _       |_|    _| |_  |" << std::endl;
    yield();
    std::cout << "|   |_|     |_|      | |     | |_  |" << std::endl;
  }
};

struct B : public Coroutine {
  void call() {
    std::cout << "|                                  |" << std::endl;
    yield();
    std::cout << "|  _| |_   _| |_      _    |_   _| |" << std::endl;
    yield();
    std::cout << "|                    |_|     |___| |" << std::endl;
    yield();
    std::cout << "|                                  |" << std::endl;
    yield();
    std::cout << "|__________________________________|" << std::endl;
  }
};

struct C : public Coroutine {
  void call() {
    std::cout << "|                     _       _    |" << std::endl;
    yield();
    std::cout << "| |_   _| |_   _|    | |     | |   |" << std::endl;
  }

  void operator++(int) {
    std::cout << "| ++It - The Italian C++ Community |" << std::endl;
    std::cout << "|__________________________________|" << std::endl;
  }
};


int main() {

  A a;
  B b;
  C c;
  for (size_t i = 0; i<10; ++i) {
    a();
    b();
    c();
  }

  c++; // An entire operator overloading to write 'c++'? Worth it!
}

Final words

Coroutines provide a powerful abstraction to offer the same level of concurrency one would get with asynchronous callbacks by offering at the same time a chance to write more maintainable code. At the time of writing this article boost offers context, coroutine and fiber libraries. As we’ve seen boost::context provides the foundation for userland context switches, boost::coroutine2 offers coroutines support (which conceptually have no need of synchronization whatsoever since they implement a nonpreemptive cooperative multitasking) and boost::fiber which builds on boost::context to add a scheduling mechanism: each time a fiber yields, control is given back to a scheduler manager which decides the next execution strategy (cfr. N4024).

As usual it is up to the programmer to carefully choose which abstractions are to be used in a specific context.

References and credits

Special thanks to the ++it community and Oliver Kowalke for providing insights and reviews of parts of this article.

]]>
6862
C++ Day 2016 https://www.italiancpp.org/event/cppday16/ Sat, 29 Oct 2016 06:30:00 +0000 http://www.italiancpp.org/?post_type=tribe_events&p=6326
 

dsc01377

Tutte le foto

 

Segui i link in agenda per slides/demo delle sessioni

 

 

L’Italian C++ Community & Develer hanno presentato:

slide-cppday16

Una giornata gratuita, 100% made in Italy, completamente dedicata al C++!

Sessioni frontali, un Workshop, un Coding Dojo, un’Unconference, un Panel Q/A e 1/3 dell’evento dedicato al networking!
80+ partecipanti.
 
dotnetpodcast

Ascolta un podcast su questo evento


 

Programma della giornata (collegamenti a materiale e video):

quando quanto track 1 track 2
8.30 – 9.00 30' Registrazione
9.00 – 9.45 45' Presentazione della giornata
Marco Arena
-
10.00 – 11.00 60' C++17 per tutti i giorni
Marco Arena
Lo stack grafico di Qt
Luca Ottaviano
11.00 – 11.45 45' Coffee Break
11.45 – 12.45 60' C++ e Kafka
Gian Lorenzo Meocci
C++ Coding Dojo
12.45- 14.00 75' Pranzo
14.00 – 15.00 60' Introduzione a Modern C++
Raffaele Rialdi
Data Oriented Design: alte performance in C++
Daniele Maccioni
15.15 – 16.15 60' Le API e il miele
Marco Foco
C++ Unconference
16.15 – 16.45 30' Coffee Break
16.45 – 17.30 45' Ask Us Everything -
17.30 – 18.00 30' Saluti
Marco Arena
-

Dalle 14 alle 16.15 è stato possibile partecipare al workshop gratuito:

Introduzione al C++ Template Metaprogramming

Facilitato da Eugenio Bargiacchi.

 

L’evento è stato supportato da:

logo-jetbrains

 
L’evento è stato sponsorizzato da:

soft2000

L’evento è stato co-organizzato con:

develer-logo

]]>
6326
Italian C++ Conference 2016 https://www.italiancpp.org/event/conference-2016/ Sat, 14 May 2016 06:30:00 +0000 http://www.italiancpp.org/?post_type=tribe_events&p=5775

Tutte le foto

 

Video delle sessioni

 

Questo evento è piaciuto?

  

Leggi il post sull’evento

 

La prima conferenza italiana completamente dedicata al C++

100+ partecipanti

logo-cpp

Sabato 14 Maggio all’Università Bicocca di Milano

 

Con la partecipazione straordinaria di James McNellis,
dal Visual C++ Team di Redmond!

james-mc-nellis

 

dotnet-podcast

Ascolta un breve podcast sull’evento!

 

Programma della giornata (collegamenti a slides e video):  

quando quanto cosa chi
8.30 – 9.00 30' Registrazione -
9.00 – 9.15 15' Presentazione della giornata Marco Arena
9.30 – 10.30 60' An Introduction to C++ Coroutines James McNellis
10.40 – 11.40 60' Da un grande C++ derivano grandi responsabilità Marco Arena
11.40 – 12.00 20' Coffee Break -
12.00 – 13.00 60' REST e Websocket in C++ diventano semplici e produttivi con il REST SDK Raffaele Rialdi
13.00 – 13.30 30' Pranzo -
13.30 – 14.00 30' Questione di Codice: Come possiamo rendere più semplice la scrittura
il test e il deploy di codice C++ complesso?
RogueWave Software
14.15 – 15.15 60' No More Pointers!
New ideas for teaching and learning modern C++
Marco Foco
15.30 – 16.30 60' Adventures in a Legacy Codebase James McNellis
16.30 – 16.50 20' Break -
16.50 – 17.30 40' Ask Us Everything Tutti gli speakers
17.45 – 18.00 15' Saluti Marco Arena
Sponsorizzato da:
rogue-wave

 

 
Supportato da:
 

oreilly-logo

 
jb-logo

]]>
5775
Codemotion Milano 2015 https://www.italiancpp.org/event/codemotion-milano-2015/ Fri, 20 Nov 2015 23:00:00 +0000 http://www.italiancpp.org/?post_type=tribe_events&p=5399

Marco Arena ha presentato:

“Perché nel 2015 parliamo ancora di C++?”

 

C__Data_Users_DefApps_AppData_INTERNETEXPLORER_Temp_Saved Images_12273560_1026450354043939_1786806679044325217_o

Feedback alla sessione

]]>
5399
Folding Expressions https://www.italiancpp.org/2015/06/15/folding-expressions/ https://www.italiancpp.org/2015/06/15/folding-expressions/#comments Mon, 15 Jun 2015 16:32:38 +0000 http://www.italiancpp.org/?p=4980 People familiar with the new features C++11 brought to the C++ programming language should know what a variadic template is and why they’re important. Variadic templates can have a variable number of parameters of any type:

template <typename... Types> class tuple;

This not only brings type safety to the code but also ensures that all the variadic arguments handling is performed at compile-time. Before their introduction, in order to have a template accepting a variable number of template parameters, programmers were used to write verbose code like:

template<typename T0>
void function( T0 arg0 );

template<typename T0, typename T1>
void function( T0 arg0, T1 arg1 );

template<typename T0, typename T1, typename T2>
void function( T0 arg0, T1 arg1, T2 arg2 );

template<typename T0, typename T1, typename T2, typename T3>
void function( T0 arg0, T1 arg1, T2 arg2, T3 arg3 );

...

Template parameter packs went hand-in-hand with variadic templates and together with constant expressions they enabled a recursive-like style of coding to create more complex compile-time operations:

#include <iostream>
#include <array>

template<size_t... Is> struct seq{};
template<size_t N, size_t... Is>
struct gen_seq : gen_seq<N-1, N-1, Is...>{};
template<size_t... Is>
struct gen_seq<0, Is...> : seq<Is...>{};

template<size_t N1, size_t... I1, size_t N2, size_t... I2>
// Expansion pack
constexpr std::array<int, N1+N2> concat(const std::array<int, N1>& a1, 
        const std::array<int, N2>& a2, seq<I1...>, seq<I2...>){
  return {{ a1[I1]..., a2[I2]... }};
}

template<size_t N1, size_t N2>
// Initializer for the recursion
constexpr std::array<int, N1+N2> concat(const std::array<int, N1>& a1, 
                                       const std::array<int, N2>& a2){
  return concat(a1, a2, gen_seq<N1>{}, gen_seq<N2>{});
}

int main() {
    constexpr std::array<int, 3> a1 = {{1,2,3}};
    constexpr std::array<int, 2> a2 = {{4,5}};

    constexpr std::array<int,5> res = concat(a1,a2);
    for(int i=0; i<res.size(); ++i)
        std::cout << res[i] << " "; // 1 2 3 4 5

    return 0;
}

Exploiting a constexpr overload of the operator[] the code above generates an integer sequence, aggregate-initializes an std::array and concatenates the input arrays at compile time (details of the operations involved are available at this link).

The integer generation sequence construct was then provided by the standard library itself in C++14 with std::integer_sequence.

These features allowed new ways to exploit templates, anyway parameter packs could only be used and expanded in a strictly-defined series of contexts. For instance, something like the following wasn’t allowed:

template<typename T>
void printer(T arg) {
    std::cout << arg << " ";
}

template<typename... Args>
static void function(Args &&... args) {
    (printer(std::forward<Args>(args)) , ...);
}

Anyway one of those restricted contexts was brace-init-lists, therefore workarounds to have parameter packs be expanded were immediately deployed:

template<typename T>
void printer(T arg) {
    std::cout << arg << " ";
}

template<typename... Args>
static void function(Args &&... args) {
    // Expand the pack into a brace-init-list while discarding the return
    // values and filling an unused array
    int unusedVar[] = { 0, 
              ( (void) printer(std::forward<Args>(args)), 0) ... };
}


C++17 ~ fold expressions

C++17, scheduled by 2017 at the time of writing, will introduce fold expressions into play and significantly broaden parameter packs scopes of use (cfr. N4191 paper).

As listed in cppreference, at the time of writing, there are four kinds of fold expressions:

  • Unary right fold
    ( pack op ... )
  • Unary left fold
    ( ... op pack )
  • Binary right fold
    ( pack op ... op init )
  • Binary left fold
    ( init op ... op pack )

being their respective expansions:

  • E_1 op (... op (E_N-1 op E_N))
  • ((E_1 op E_2) op ...) op E_N
  • E_1 op (... op (E_N−1 op (E_N op init)))
  •  (((init op E_1) op E_2) op ...) op E_N

In binary folds the op operators must be the same and init represents an expression without an unexpanded parameter pack (e.g. the init value for the expanded expression).

With fold expressions writing a printer construct becomes straightforward:

#include <iostream>

template<typename F, typename... T>
void for_each(F fun, T&&... args)
{
    (fun (std::forward<T>(args)), ...);
}

int main() {
     for_each([](auto i) { std::cout << i << " "; }, 4, 5, 6); // 4 5 6
}

The sample above uses fold expressions together with the comma operator to create a simple function that calls the provided lambda per each one of the supplied arguments with perfect forwarding.

A caveat relative to the previous example though: unary right fold expressions and unary left fold expressions applied with the comma operator do yield different expressions but their evaluation order remains the same, e.g.

#include <iostream>
#include <memory>

template<typename F, typename... T>
void for_each1(F fun, T&&... args)
{
    (fun (std::forward<T>(args)), ...);
}

template<typename F, typename... T>
void for_each2(F fun, T&&... args)
{
    (..., fun (std::forward<T>(args)));
}

int main()
{
     for_each1([](auto i) { std::cout << i << " "; }, 4, 5, 6); // 4 5 6
     std::cout << std::endl;
     for_each2([](auto i) { std::cout << i << " "; }, 4, 5, 6); // 4 5 6
}

It has to be noted that one of the main reasons fold expressions were accepted as a C++17 proposal is because of their use in concepts:

template <typename T>
  concept bool Integral = std::is_integral<T>::value;

template <Integral... Ts> // A constrained-parameter pack
  void foo(Ts...);

template <typename... Ts>
  requires Integral<Ts>... // error: requirement is ill-formed
void foo(Ts...);

The problem boiled down to the same issue we talked of some paragraphs ago: the parameter pack cannot expand in that context. Fold expressions provide an elegant and effective way to deal with this issue instead of resorting to other constexpr machineries to ensure requirements are met:

template<typename... Ts>
  requires (Integral<Ts> && ...)
void foo(Ts...);


 

References and sources:
N4191 – Folding expressions
cppreference
constexpr flatten list of std::array into array
Variadic template pack expansion
Why doesn’t a left fold expression invert the output of a right fold expression

Thanks to Marco Arena and Andy for the quick review of this article.

]]>
https://www.italiancpp.org/2015/06/15/folding-expressions/feed/ 2 4980