L'operatore di assegnazione è definito per avere l'effetto:
function(std::forward<F>(f)).swap(*this);
(14882: 2011 20.8.11.2.1 par.18)
Il costruttore che questo riferimenti,
template <class F> function(F f);
richiede:
F
sarà CopyConstructible
. f
deve essere Callable
(20.8.11.2) per il tipo di argomento ArgTypes
e il tipo di ritorno R
.
dove Callable
è definito come segue:
Un oggetto richiamabile f
di tipo F
è Callable
per tipi di argomento ArgTypes
e di ritorno di tipo R
se l'espressione INVOKE(f, declval<ArgTypes>()..., R)
, considerata come operando non valutata (punto 5) , è ben formato (20.8.2).
INVOKE
, a sua volta, è defined as:
Definire INVOKE (f, t1, t2, ..., tN) come segue:
- ... casi per la gestione delle funzioni membro omessi qui ...
f(t1, t2, ..., tN)
in tutti gli altri casi .
Definire INVOKE(f, t1, t2, ..., tN, R)
come static_cast<void>(INVOKE(f, t1, t2, ..., tN))
se R
è cvvoid
, altrimenti INVOKE(f, t1, t2, ..., tN)
implicitamente convertito in R
.
Poiché la definizione INVOKE
diventa una chiamata di funzione normale, in questo caso, gli argomenti possono essere converted: Se il vostro std::function<void(const int&)>
accetta un const int&
allora può essere convertita in un int
per la chiamata. L'esempio che segue riunisce con clang++ -std=c++14 -stdlib=libc++ -Wall -Wconversion
:
int main() {
std::function<void(const int& i)> f;
f = [](int i) -> void { std::cout << i << std::endl; };
f(2);
return 0;
}
il tipo di ritorno (void
) è gestita dalla speciale caso static_cast<void>
per la definizione INVOKE
.
noti, tuttavia, che, al momento della scrittura seguente genera un errore quando si compila con clang++ -std=c++1z -stdlib=libc++ -Wconversion -Wall
, ma non se compilato con clang++ -std=c++1z -stdlib=libstdc++ -Wconversion -Wall
:
int main() {
std::function<void(const int& i)> f;
f = [](int i) -> int { std::cout << i << std::endl; return i;};
f(2);
return 0;
}
Ciò è dovuto libc++
attuare il comportamento come specificato in C++ 14, anziché lo amended behaviour descritto sopra (grazie a @Jonathan Wakely per averlo indicato). @Arunmu descrive il tratto di tipo libstdc++
responsabile della stessa cosa in his post.A questo proposito, le implementazioni possono comportarsi in modo leggermente diverso quando si gestiscono le callebles con i tipi di ritorno void
, a seconda che implementino C++ 11, 14 o qualcosa di più recente.
Inoltre: esiste un termine specifico per ciò che sto descrivendo qui o è * tipo di conversione * corretto? – anderas
Sembra un po 'come covarianza e controvarianza, ma penso che questi termini siano usati solo tra classi di base e derivate in OO. – Quentin
Non ho il problema. Se hai una funzione con firma 'void (const int & i)', puoi inoltrare nel suo corpo una funzione con firma 'int (int)'? Sì. Non stai violando i qualificatori di cv (beh, stai copiando il valore, quindi ...) e puoi liberamente scartare il valore restituito. L'opposto sarebbe stato invece sbagliato e non funziona davvero. Quindi, qual è il problema attuale? – skypjack