Stavo leggendo il std::thread documentation at cppreference (non sempre accurato al 100%, lo so) e ho notato la seguente definizione per il comportamento di std::thread
quando è passato un "pointer-to-data-member" (non "puntatore-a-membro-funzione") come primo parametro (f
) e un oggetto della classe richiesta come secondo argomento (t1
dopo la copia locale del thread-storage):std :: thread con puntatore al membro dati
Se N == 1 e f è puntatore a un oggetto dati membro di una classe, quindi è accessibile. Il valore dell'oggetto è ignorato. Effettivamente, viene eseguito il seguente codice: t1. * F se e il tipo di t1 è T, riferimento a T o riferimento a tipo derivato da T. (* t1). * F altrimenti.
Ora, non ho intenzione di utilizzare std::thread
in questo modo, ma sono sconcertato da questa definizione. Apparentemente, l'unica cosa che succede è che si accede al membro dati e il valore viene ignorato, il che non sembra che possa avere effetti collaterali osservabili, il che significa (per quanto posso dire) che potrebbe anche essere un no-op. (Potrei mancare qualcosa di ovvio ...?)
In un primo momento, ho pensato che si trattasse di un errore di stampa e intendevo dire che il membro dati è stato richiamato e quindi chiamato (poiché potrebbe essere un oggetto chiamabile, anche se non è una funzione), ma ho provato con il seguente codice nel GCC-4.7 e in effetti non v'è alcuna chiamata:
#include <iostream>
#include <thread>
struct S
{
void f() {
std::cout << "Calling f()" << std::endl;
}
struct {
void operator()() {
std::cout << "Calling g()" << std::endl;
}
} g;
};
int main(int, char**)
{
S s;
s.f(); // prints "Calling f()"
s.g(); // prints "Calling g()"
std::cout << "----" << std::endl;
auto x = &S::f; // ptr-to-mem-func
auto y = &S::g; // ptr-to-data-mem
(s.*x)(); // prints "Calling f()"
(s.*y)(); // prints "Calling g()"
std::cout << "----" << std::endl;
std::thread t(x, &s);
t.join();
// "Calling f()" printed by now
std::thread u(y, &s);
u.join();
// "Calling g()" not printed
return 0;
}
c'è uno scopo a questa definizione, che non sembra realizzare qualcosa? Perché invece non fare passare un atto "pointer-to-data-member-callable" come una "funzione pointer-to-member" e rendere un errore "pointer-to-data-member-nonclable" un errore? In effetti, sembra che questo sarebbe il modo più semplice per implementarlo, dal momento che chiamare un "pointer-to-data-member-callable" ha una sintassi equivalente a chiamare "pointer-to-member-function" in altri contesti (a meno che non ci sia qualcosa nelle vaghezze della specializzazione dei template e delle regole di SFINAE che rende difficile trattarli in modo equivalente ...?)
Questo non è qualcosa di cui ho bisogno per il codice reale, ma il fatto che questa definizione esista mi fa sospettare che Mi manca qualcosa di fondamentale, che mi preoccupa ... qualcuno può illuminarmi di questo?
+1 Questa formulazione deriva dalla definizione di "INVOKE", che è riportata in 20.8.2 della norma. C'è una domanda con lo stesso intento del tuo in particolare su questa formulazione nella definizione "INVOKE": http://stackoverflow.com/questions/12638393/why-does-invoke-facility-in-the-c11-standard-refer -to-data-members – jogojapan