Domanda Usando `std :: function ` per chiamare la funzione non void


Qualche tempo fa ho usato std::function più o meno così:

std::function<void(int)> func = [](int i) -> int { return i; };

Fondamentalmente, l'ho fatto perché volevo memorizzare diversi oggetti funzione in a std::function, ma non volevo limitare i tipi di ritorno di queste funzioni. Visto che sembrava funzionare, ci sono andato. Ma non sono convinto che sia sicuro da usare, e non sono stato in grado di trovare alcuna documentazione su di esso. Qualcuno sa se questo uso è legittimo? O più in generale, quali sono le regole per l'oggetto che possono essere tranquillamente assegnate a std::function?

modificare

Per chiarire, il problema che mi riguarda è che la funzione lambda restituisce un int, mentre func è dichiarato con tipo di reso void. Non sono sicuro se questo è OK, soprattutto una volta chiamata func() è fatto.


16
2018-02-18 08:37


origine


risposte:


Il tuo codice ha un comportamento indefinito. Potrebbe funzionare o meno come previsto. La ragione per cui ha un comportamento indefinito è a causa di 20.8.11.2.1 [func.wrap.func.con] / p7:

Richiede:  F deve essere CopyConstructible. f deve essere Callable (20.8.11.2) per i tipi di argomenti ArgTypes e restituire il tipo R.

Per f essere richiamabile per tipo di reso R, f deve restituire qualcosa implicitamente convertibile al tipo di ritorno del std::function (void nel tuo caso). E int non è implicitamente convertibile in void.

Mi aspetto che il tuo codice funzioni sulla maggior parte delle implementazioni. Tuttavia su almeno una implementazione (libc ++), non riesce a compilare:

test.cpp:7:30: error: no viable conversion from 'int (int)' to 'std::function<void (int)>'
    std::function<void(int)> ff = f;
                             ^    ~

Ironia della sorte deriva da questo comportamento un'altra domanda SO.

L'altra domanda ha presentato un problema con std::function utilizzo. La soluzione a questo problema implicava l'implementazione dell'applicazione del protocollo Richiede: clausola al momento della compilazione. Al contrario, la soluzione al problema di questa domanda è ostile l'implementazione dall'applicazione del Richiede: clausola.


19
2018-02-18 17:27



Il tuo caso d'uso è ben definito in base allo standard.

Stai costruendo a std::function da un oggetto callable [1]

§20.8.11.2.1 / 7:

template<class F> function(F f);

Richiede: F deve essere CopyConstructible. f sarà Callable (20.8.11.2) per i tipi di argomenti ArgTypes   e restituire il tipo R.

Quindi è il tuo f callable?

Il §20.8.11.2 / 2 dice:

Un oggetto callable f di tipo F è Callable per i tipi di argomenti ArgTypes   e restituire il tipo R se l'espressione INVOKE (f, declval<ArgTypes>()..., R), considerato come un operando non valutato   (Clausola 5), ​​è ben formato (20.8.2).

E la definizione di INVOKE dice:

§20.8.2

  1. Definire INVOKE (f, t1, t2, ..., tN) come segue:   ... roba che si occupa di funzioni membro / puntatori var ...   - f(t1, t2, ..., tN) in tutti gli altri casi.

  2. Definire INVOKE (f, t1, t2, ..., tN, R) as INVOKE (f, t1, t2, ..., tN) convertito implicitamente in R.

E poiché qualsiasi tipo può essere convertito implicitamente in void, il tuo codice dovrebbe andare bene con un compilatore conforme agli standard. Come sottolineato da litb di seguito, non esiste una conversione implicita al vuoto, quindi non è ben definito.

[1]: Penso che la lambda valga come oggetto callabile qui, anche se non ho un riferimento per questo. Il tuo lambda potrebbe anche essere usato come puntatore a funzione in quanto non cattura alcun contesto


1
2018-02-18 12:15



Sembra che potrebbe essere ok per le funzioni anonime.

Citazione da http://www.alorelang.org/release/0.5/doc/std_function.html (questo non è dalla libreria standard di C ++, tuttavia sembra che stiano usando qualcosa di simile nei collegamenti fino a C ++)

Gli oggetti funzione possono essere creati solo con una definizione di funzione, un'espressione di funzione anonima o accedendo a un metodo associato usando l'operatore punto (.).

Un altro modo in cui ciò potrebbe essere fatto è di memorizzare il puntatore di funzione in auto come visto qui: http://en.wikipedia.org/wiki/Anonymous_function (Sezione C ++)


0
2018-02-18 08:49