2015-08-19 8 views
5

Non uguale ma probabilmente correlato a this question about static initializers.Perché un lambda (che acquisisce 'this') in un membro funzione-try-block handler non può accedere ai membri di dati privati ​​in VC++ 2013?

Ecco le prime due funzioni compilare bene, e l'ultima non lo fa in VC++, ma lo fa in clang e gcc:

class A { 
protected: 
    std::string protected_member = "yay"; 
public: 
    void withNormalBlock(); 
    void withFunctionBlock(); 
    void noLambda(); 
}; 


void A::withNormalBlock() { 
    try { 
     throw std::exception(); 
    } catch (...) { 
     [this]() { 
      std::cout << protected_member << std::endl; 
     }(); 
    } 
} 

void A::noLambda() try { 
    throw std::exception(); 
} catch (...) { 
    std::cout << protected_member << std::endl; 
} 

void A::withFunctionBlock() try { 
    throw std::exception(); 
} catch (...) { 
    [this]() { 
     // this line is the problem: 
     std::cout << protected_member << std::endl; 
    }(); 
} 
  • in clang (OK)
  • in gcc (OK)
  • in vc++ (error C2248: 'A::protected_member' : cannot access protected member declared in class 'A')
  • vc++ 2015 - accordo stesso

Non riesco a trovare nulla nello standard per suggerire che il blocco gestore/catch di un blocco funzione-try debba essere esente dall'ambito della funzione o che il tipo di chiusura lambda debba cambiare. Il codice viene compilato se il tipo di accesso viene modificato a tutti i pubblici.

Quale potrebbe essere la causa principale? È un bug o è qualcosa di specifico nelle impostazioni del compilatore che potrebbe essere cambiato?

+0

Sembra che si tratta di un bug, lo standard non menziona nulla circa la portata cattura essendo al di fuori dell'ambito della funzione membro della classe e sono riuscito a trovare la prova che il lambda è generato al di fuori dell'ambito della funzione membro della classe. Dovresti segnalarlo. –

+0

Ora che il mio modulo di feedback non si blocca più, ho: https://connect.microsoft.com/VisualStudio/feedback/details/1749162 – MechEngineer

risposta

2

sembra che questo sia un bug e la lambda nello scope catch viene generato al di fuori dell'ambito della classe. Ho provato a dimostrarlo con i typeidi ma i nomi lambda di Visual Studio sono stranamente mutilati e il nome stesso non prova nulla. Tuttavia, i codici di errore generati dal seguente frammento mostrano che i nomi si differenziano: uscita

#include <iostream> 
#include <typeinfo> 

class Foo { 
private: 
public: 
    void testLambda() 
    try { 
     auto tryScope = [this]() {}; 
     void (*p)() = tryScope; 
    } 
    catch(...) 
    { 
     auto catchScope = [this]() {}; 
     void (*p)() = catchScope; 
    } 

}; 

Errore:

(10): error C2440: 'initializing' : cannot convert from 'Foo::testLambda::<lambda_8a3a8afea7359de4568df0e75ead2a56>' to 'void (__cdecl *)(void)' (15): error C2440: 'initializing' : cannot convert from '<lambda_8cbc08e7748553fb5ae4e39184491e92>' to 'void (__cdecl *)(void)'

+0

Ha! colto in flagrante. Bello ... ancora più stranamente, la combinazione con l'altra risposta mi ha dato questo: 'Foo :: testLambda :: CatchClosure', che sembrerebbe indicare che è solo lambda ... – MechEngineer

+0

@MechEngineer bene hai già capito bene nella domanda che il problema era puramente correlato a lambda, ho provato 'typeid' ma i nomi di Visual Studio per lambda sembrano essere strani e non includono gli spazi dei nomi (non sono sicuro il motivo per cui non sono uguali a quelli nell'errore) ma questa compilation l'errore ha effettivamente esposto la differenza. –

3

Direi che si tratta di un bug del compilatore. Segnala lo stesso errore anche in VS2015. Curiosamente, un tentativo di simulare in modo esplicito le funzionalità di lambda funziona senza problemi in VS2015

class A 
{ 
protected: 
    std::string protected_member = "yay"; 
public: 
    void withFunctionBlock(); 
}; 

void A::withFunctionBlock() try 
{ 
    throw std::exception(); 
} 
catch (...) 
{ 
    struct Closure { 
    Closure(A *this_) : this_(this_) {} 
    void operator()() const { std::cout << this_->protected_member << std::endl; } 
    A *this_; 
    }; 
    Closure(this)(); 
} 

Mi chiedo cosa VS compilatore C++ fa in maniera diversa sotto il cofano ...

+0

Dopo tentativi disperati in realtà ho trovato un modo per far sì che Visual Studio ammetta che genera il lambda in l'ambito sbagliato: D –

Problemi correlati