Condividi tramite


/permissive- (Conformità agli standard)

Specificare la modalità di conformità degli standard al compilatore. Usare questa opzione per identificare e risolvere i problemi di conformità nel codice, per renderla più corretta e più portabile.

Sintassi

/permissive-
/permissive

Osservazioni:

L'opzione /permissive- è supportata in Visual Studio 2017 e versioni successive. /permissive è supportato in Visual Studio 2019 versione 16.8 e successive.

È possibile usare l'opzione del /permissive- compilatore per specificare il comportamento del compilatore conforme agli standard. Questa opzione disabilita i comportamenti permissivi e imposta le opzioni del /Zc compilatore per una rigorosa conformità. Nell'IDE questa opzione rende anche il codice non conforme al motore IntelliSense.

L'opzione /permissive- usa il supporto della conformità nella versione corrente del compilatore per determinare quali costrutti di linguaggio non sono conformi. L'opzione non determina se il codice è conforme a una versione specifica dello standard C++. Per abilitare tutto il supporto del compilatore implementato per lo standard bozza più recente, usare l'opzione /std:c++latest . Per limitare il supporto del compilatore allo standard C++20 attualmente implementato, usare l'opzione /std:c++20 . Per limitare il supporto del compilatore allo standard C++17 attualmente implementato, usare l'opzione /std:c++17 . Per limitare il supporto del compilatore in modo più simile allo standard C++14, usare l'opzione /std:c++14 , ovvero l'impostazione predefinita.

L'opzione /permissive- viene impostata in modo implicito dall'opzione /std:c++latest a partire da Visual Studio 2019 versione 16.8 e nella versione 16.11 dall'opzione /std:c++20 . /permissive- è obbligatorio per il supporto dei moduli C++20. Il codice non richiede il supporto dei moduli, ma richiede altre funzionalità abilitate in /std:c++20 o /std:c++latest. È possibile abilitare in modo esplicito il supporto delle estensioni Microsoft usando l'opzione /permissive senza il trattino finale. L'opzione /permissive deve venire dopo qualsiasi opzione che imposta /permissive- in modo implicito.

Per impostazione predefinita, l'opzione /permissive- è impostata nei nuovi progetti creati da Visual Studio 2017 versione 15.5 e versioni successive. Non è impostato per impostazione predefinita nelle versioni precedenti. Quando l'opzione è impostata, il compilatore genera errori di diagnostica o avvisi quando vengono rilevati costrutti di linguaggio non standard nel codice. Questi costrutti includono alcuni bug comuni nel codice pre-C++11.

L'opzione /permissive- è compatibile con quasi tutti i file di intestazione dei Kit di Windows più recenti, ad esempio Software Development Kit (SDK) o Windows Driver Kit (WDK), a partire da Windows Fall Creators SDK (10.0.16299.0). Le versioni precedenti dell'SDK potrebbero non essere compilate /permissive- per diversi motivi di conformità del codice sorgente. Il compilatore e gli SDK vengono forniti in sequenze temporali di rilascio diverse, quindi ci sono alcuni problemi rimanenti. Per problemi specifici relativi ai file di intestazione, vedi Problemi di intestazione di Windows di seguito.

L'opzione /permissive- imposta le /Zc:referenceBindingopzioni , /Zc:strictStringse /Zc:rvalueCast sul comportamento conforme. Per impostazione predefinita, queste opzioni non sono conformi. È possibile passare opzioni specifiche /Zc dopo /permissive- nella riga di comando per eseguire l'override di questo comportamento.

Nelle versioni del compilatore che iniziano in Visual Studio 2017 versione 15.3, l'opzione /permissive- imposta l'opzione /Zc:ternary . Il compilatore implementa anche altri requisiti per la ricerca dei nomi in due fasi. Quando l'opzione /permissive- è impostata, il compilatore analizza le definizioni di modelli di funzione e classe e identifica i nomi dipendenti e non dipendenti usati nei modelli. In questa versione viene eseguita solo l'analisi delle dipendenze dei nomi.

A partire da Visual Studio 2022 Update 17.6, l'opzione /permissive- imposta le /Zc:lambda opzioni e /Zc:externConstexpr . Nelle versioni /permissive- precedenti non ne è stato impostato uno.

Le estensioni specifiche dell'ambiente e le aree del linguaggio che lo standard lasciano invariate per l'implementazione non sono interessate da /permissive-. Ad esempio, le parole chiave di gestione delle eccezioni specifiche di Microsoft, la convenzione di chiamata e le direttive o gli attributi specifici __declspecpragma del compilatore non vengono contrassegnati dal compilatore in /permissive- modalità .

Il compilatore MSVC nelle versioni precedenti di Visual Studio 2017 non supporta tutto il codice conforme agli standard C++11, C++14 o C++17. A seconda della versione di Visual Studio, l'opzione /permissive- potrebbe non rilevare problemi in alcuni aspetti della ricerca dei nomi in due fasi, associando un riferimento non const a un riferimento temporaneo, trattando copy init come init diretto, consentendo più conversioni definite dall'utente nell'inizializzazione o token alternativi per gli operatori logici e altre aree di conformità non supportate. Per altre informazioni sui problemi di conformità in Visual C++, vedere Nonstandard Behavior. Per sfruttare al meglio /permissive-, aggiornare Visual Studio alla versione più recente.

Come correggere il codice

Di seguito sono riportati alcuni esempi di codice rilevati come non conformi quando si usa /permissive-, insieme ai modi suggeriti per risolvere i problemi.

Usare default come identificatore nel codice nativo

void func(int default); // Error C2321: 'default' is a keyword, and
                        // cannot be used in this context

Cercare i membri nella base dipendente

template <typename T>
struct B
{
    void f() {}
    template <typename U>
    struct S { void operator()(){ return; } };
};

template <typename T>
struct D : public B<T> // B is a dependent base because its type
                       // depends on the type of T.
{
    // One possible fix for non-template members and function
    // template members is a using statement:
    // using B<T>::f;
    // If it's a type, don't forget the 'typename' keyword.

    void g()
    {
        f(); // error C3861: 'f': identifier not found
        // Another fix is to change the call to 'this->f();'
    }

    void h()
    {
        S<int> s; // C2065 or C3878
        // Since template S is dependent, the type must be qualified
        // with the `typename` keyword.
        // To fix, replace the declaration of s with:
        // typename B<T>::template S<int> s;
        // Or, use this:
        // typename D::template S<int> s;
        s();
    }
};

void h() {
    D<int> d;
    d.g();
    d.h();
}

Uso di nomi qualificati nelle dichiarazioni dei membri

struct A {
    void A::f() { } // error C4596: illegal qualified name in member
                    // declaration.
                    // Remove redundant 'A::' to fix.
};

Inizializzare più membri dell'unione in un inizializzatore membro

union U
{
    U()
        : i(1), j(1) // error C3442: Initializing multiple members of
                     // union: 'U::i' and 'U::j'.
                     // Remove all but one of the initializations to fix.
    {}
    int i;
    int j;
};

Regole di ricerca nome amico nascoste

Una dichiarazione all'esterno di una classe può rendere visibile un amico nascosto:

// Example 1
struct S {
    friend void f(S *);
};
// Uncomment this declaration to make the hidden friend visible:
// void f(S *); // This declaration makes the hidden friend visible

using type = void (*)(S *);
type p = &f; // error C2065: 'f': undeclared identifier.

L'uso di valori letterali nullptr può impedire la ricerca dipendente dagli argomenti:

// Example 2
struct S {
    friend void f(S *);
};
void g() {
    // Using nullptr instead of S prevents argument dependent lookup in S
    f(nullptr); // error C3861: 'f': identifier not found

    S *p = nullptr;
    f(p); // Hidden friend now found via argument-dependent lookup.
}

È possibile abilitare le regole di ricerca dei nomi friend nascoste indipendentemente /permissive da usando /Zc:hiddenFriend. Se si desidera un comportamento legacy per la ricerca di nomi friend nascosti, ma in caso contrario si vuole /permissive- un comportamento, usare l'opzione /Zc:hiddenFriend- .

Usare le enumerazioni con ambito nei limiti di matrice

enum class Color {
    Red, Green, Blue
};

int data[Color::Blue]; // error C3411: 'Color' is not valid as the size
                       // of an array as it is not an integer type.
                       // Cast to type size_t or int to fix.

Usare per ogni codice nativo

void func() {
    int array[] = {1, 2, 30, 40};
    for each (int i in array) // error C4496: nonstandard extension
                              // 'for each' used: replace with
                              // ranged-for statement:
                              // for (int i: array)
    {
        // ...
    }
}

Uso degli attributi ATL

Gli attributi ATL specifici di Microsoft possono causare problemi in /permissive-:

// Example 1
[uuid("594382D9-44B0-461A-8DE3-E06A3E73C5EB")]
class A {};

È possibile risolvere il problema usando il __declspec modulo:

// Fix for example 1
class __declspec(uuid("594382D9-44B0-461A-8DE3-E06A3E73C5EB")) B {};

Un esempio più complesso:

// Example 2
[emitidl];
[module(name="Foo")];

[object, local, uuid("9e66a290-4365-11d2-a997-00c04fa37ddb")]
__interface ICustom {
    HRESULT Custom([in] longl, [out, retval] long*pLong);
    [local] HRESULT CustomLocal([in] longl, [out, retval] long*pLong);
};

[coclass, appobject, uuid("9e66a294-4365-11d2-a997-00c04fa37ddb")]
class CFoo : public ICustom
{};

La risoluzione richiede passaggi di compilazione aggiuntivi. In questo caso, creare un file IDL:

// Fix for example 2
// First, create the *.idl file. The vc140.idl generated file can be
// used to automatically obtain a *.idl file for the interfaces with
// annotation. Second, add a midl step to your build system to make
// sure that the C++ interface definitions are outputted.
// Last, adjust your existing code to use ATL directly as shown in
// the atl implementation section.

-- IDL  FILE--
import "docobj.idl";

[object, local, uuid(9e66a290-4365-11d2-a997-00c04fa37ddb)]
interface ICustom : IUnknown {
    HRESULT Custom([in] longl, [out,retval] long*pLong);
    [local] HRESULT CustomLocal([in] longl, [out,retval] long*pLong);
};

[ version(1.0), uuid(29079a2c-5f3f-3325-99a1-3ec9c40988bb) ]
library Foo {
    importlib("stdole2.tlb");
    importlib("olepro32.dll");

    [version(1.0), appobject, uuid(9e66a294-4365-11d2-a997-00c04fa37ddb)]
    coclass CFoo { interface ICustom; };
}

-- ATL IMPLEMENTATION--
#include <idl.header.h>
#include <atlbase.h>

class ATL_NO_VTABLE CFooImpl : public ICustom,
    public ATL::CComObjectRootEx<CComMultiThreadModel>
{
    public:BEGIN_COM_MAP(CFooImpl)
    COM_INTERFACE_ENTRY(ICustom)
    END_COM_MAP()
};

Argomenti dell'operatore condizionale ambigui

Nelle versioni del compilatore precedenti a Visual Studio 2017 versione 15.3, il compilatore ha accettato argomenti per l'operatore condizionale (o l'operatore ternario) ?: considerati ambigui dallo standard. In /permissive- modalità, il compilatore rilascia ora una o più diagnostica nei casi compilati senza diagnostica nelle versioni precedenti.

Gli errori comuni che possono derivare da questa modifica includono:

  • error C2593: 'operator ?' is ambiguous

  • error C2679: binary '?': no operator found which takes a right-hand operand of type 'B' (or there is no acceptable conversion)

  • error C2678: binary '?': no operator found which takes a left-hand operand of type 'A' (or there is no acceptable conversion)

  • error C2446: ':': no conversion from 'B' to 'A'

Un modello di codice tipico che può causare questo problema è quando alcune classi C forniscono sia un costruttore non esplicito da un altro tipo T che un operatore di conversione non esplicito al tipo T. La conversione del secondo argomento nel tipo del terzo argomento è una conversione valida. Quindi è la conversione del terzo argomento nel tipo del secondo argomento. Poiché entrambi sono validi, è ambiguo in base allo standard.

// Example 1: class that provides conversion to and initialization from some type T
struct A
{
    A(int);
    operator int() const;
};

extern bool cond;

A a(42);
// Accepted when /Zc:ternary or /permissive- is not used:
auto x = cond ? 7 : a; // A: permissive behavior prefers A(7) over (int)a
// Accepted always:
auto y = cond ? 7 : int(a);
auto z = cond ? A(7) : a;

Esiste un'eccezione importante a questo modello comune quando T rappresenta uno dei tipi stringa con terminazione Null (ad esempio, const char *, const char16_t *e così via) e l'argomento effettivo di ?: è un valore letterale stringa di tipo corrispondente. C++17 ha modificato la semantica da C++14. Di conseguenza, il codice nell'esempio 2 viene accettato /std:c++14 in e rifiutato in /std:c++17 o versione successiva quando /Zc:ternary viene usato o /permissive- .

// Example 2: exception from the above
struct MyString
{
    MyString(const char* s = "") noexcept;  // from char*
    operator const char* () const noexcept; //   to char*
};

extern bool cond;

MyString s;
// Using /std:c++14, /permissive- or /Zc:ternary behavior
// is to prefer MyString("A") over (const char*)s
// but under /std:c++17 this line causes error C2445:
auto x = cond ? "A" : s;
// You can use a static_cast to resolve the ambiguity:
auto y = cond ? "A" : static_cast<const char*>(s);

È anche possibile che vengano visualizzati errori negli operatori condizionali con un argomento di tipo void. Questo caso può essere comune nelle macro simili a ASSERT.

// Example 3: void arguments
void myassert(const char* text, const char* file, int line);
// Accepted when /Zc:ternary or /permissive- is not used:
#define ASSERT_A(ex) (void)((ex) ? 1 : myassert(#ex, __FILE__, __LINE__))
// Accepted always:
#define ASSERT_B(ex) (void)((ex) ? void() : myassert(#ex, __FILE__, __LINE__))

È anche possibile che vengano visualizzati errori nella metaprogrammazione del modello, in cui i tipi di risultati dell'operatore condizionale possono cambiare in /Zc:ternary e /permissive-. Un modo per risolvere questo problema consiste nell'usare std::remove_reference sul tipo risultante.

// Example 4: different result types
extern bool cond;
extern int count;
char  a = 'A';
const char  b = 'B';
decltype(auto) x = cond ? a : b; // char without, const char& with /Zc:ternary
const char (&z)[2] = count > 3 ? "A" : "B"; // const char* without /Zc:ternary

Ricerca del nome in due fasi

Quando l'opzione /permissive- è impostata, il compilatore analizza le definizioni di modelli di funzione e classe, identificando i nomi dipendenti e non dipendenti usati nei modelli in base alle esigenze per la ricerca del nome in due fasi. In Visual Studio 2017 versione 15.3 viene eseguita l'analisi delle dipendenze dei nomi. In particolare, i nomi non dipendenti non dichiarati nel contesto di una definizione di modello causano un messaggio di diagnostica come richiesto dagli standard ISO C++. In Visual Studio 2017 versione 15.7 viene eseguito anche il binding di nomi non dipendenti che richiedono la ricerca dipendente dall'argomento nel contesto di definizione.

// dependent base
struct B {
    void g() {}
};

template<typename T>
struct D : T {
    void f() {
        // The call to g was incorrectly allowed in VS2017:
        g();  // Now under /permissive-: C3861
        // Possible fixes:
        // this->g();
        // T::g();
    }
};

int main()
{
    D<B> d;
    d.f();
}

Se si vuole un comportamento legacy per la ricerca in due fasi, ma in caso contrario si vuole /permissive- un comportamento, aggiungere l'opzione /Zc:twoPhase- .

Problemi di intestazione di Windows

L'opzione /permissive- è troppo rigida per le versioni di Windows Kit prima di Windows Fall Creators Update SDK (10.0.16299.0) o Windows Driver Kit (WDK) versione 1709. Ti consigliamo di eseguire l'aggiornamento alle versioni più recenti di Windows Kit da usare /permissive- nel codice del driver di windows o dispositivo.

Alcuni file di intestazione in Windows April 2018 Update SDK (10.0.17134.0), Windows Fall Creators Update SDK (10.0.16299.0) o Windows Driver Kit (WDK) 1709, presentano ancora problemi che li rendono incompatibili con l'uso di /permissive-. Per risolvere questi problemi, è consigliabile limitare l'uso di queste intestazioni solo ai file di codice sorgente che li richiedono e rimuovere l'opzione /permissive- quando si compilano tali file di codice sorgente specifici.

Queste intestazioni WRL WinRT rilasciate in Windows April 2018 Update SDK (10.0.17134.0) non sono pulite con /permissive-. Per risolvere questi problemi, non usare /permissive-o usare /permissive- con /Zc:twoPhase- quando si usano queste intestazioni:

  • Problemi in winrt/wrl/async.h

    C:\Program Files (x86)\Windows Kits\10\Include\10.0.17134.0\winrt\wrl\async.h(483): error C3861: 'TraceDelegateAssigned': identifier not found
    C:\Program Files (x86)\Windows Kits\10\Include\10.0.17134.0\winrt\wrl\async.h(491): error C3861: 'CheckValidStateForDelegateCall': identifier not found
    C:\Program Files (x86)\Windows Kits\10\Include\10.0.17134.0\winrt\wrl\async.h(509): error C3861: 'TraceProgressNotificationStart': identifier not found
    C:\Program Files (x86)\Windows Kits\10\Include\10.0.17134.0\winrt\wrl\async.h(513): error C3861: 'TraceProgressNotificationComplete': identifier not found
    
  • Problema in winrt/wrl/implements.h

    C:\Program Files (x86)\Windows Kits\10\include\10.0.17134.0\winrt\wrl\implements.h(2086): error C2039: 'SetStrongReference': is not a member of 'Microsoft::WRL::Details::WeakReferenceImpl'
    

Queste intestazioni modalità utente rilasciate in Windows April 2018 Update SDK (10.0.17134.0) non sono pulite con /permissive-. Per risolvere questi problemi, non usare quando si usano /permissive- queste intestazioni:

  • Problemi in um/Tune.h

    C:\ProgramFiles(x86)\Windows Kits\10\include\10.0.17134.0\um\tune.h(139): error C3861: 'Release': identifier not found
    C:\Program Files (x86)\Windows Kits\10\include\10.0.17134.0\um\tune.h(559): error C3861: 'Release': identifier not found
    C:\Program Files (x86)\Windows Kits\10\include\10.0.17134.0\um\tune.h(1240): error C3861: 'Release': identifier not found
    C:\Program Files (x86)\Windows Kits\10\include\10.0.17134.0\um\tune.h(1240): note: 'Release': function declaration must be available as none of the arguments depend on a template parameter
    
  • Problema in um/spddkhlp.h

    C:\Program Files (x86)\Windows Kits\10\include\10.0.17134.0\um\spddkhlp.h(759): error C3861: 'pNode': identifier not found
    
  • Problemi in um/refptrco.h

    C:\Program Files (x86)\Windows Kits\10\include\10.0.17134.0\um\refptrco.h(179): error C2760: syntax error: unexpected token 'identifier', expected 'type specifier'
    C:\Program Files (x86)\Windows Kits\10\include\10.0.17134.0\um\refptrco.h(342): error C2760: syntax error: unexpected token 'identifier', expected 'type specifier'
    C:\Program Files (x86)\Windows Kits\10\include\10.0.17134.0\um\refptrco.h(395): error C2760: syntax error: unexpected token 'identifier', expected 'type specifier'
    

Questi problemi sono specifici delle intestazioni della modalità utente in Windows Fall Creators Update SDK (10.0.16299.0):

  • Problema in um/Query.h

    Quando si usa l'opzione del /permissive- compilatore, la tagRESTRICTION struttura non viene compilata a causa del case(RTOr) membro or.

    struct tagRESTRICTION
    {
         ULONG rt;
         ULONG weight;
         /* [switch_is][switch_type] */ union _URes
         {
             /* [case()] */ NODERESTRICTION ar;
             /* [case()] */ NODERESTRICTION or;  // error C2059: syntax error: '||'
             /* [case()] */ NODERESTRICTION pxr;
             /* [case()] */ VECTORRESTRICTION vr;
             /* [case()] */ NOTRESTRICTION nr;
             /* [case()] */ CONTENTRESTRICTION cr;
             /* [case()] */ NATLANGUAGERESTRICTION nlr;
             /* [case()] */ PROPERTYRESTRICTION pr;
             /* [default] */  /* Empty union arm */
         } res;
    };
    

    Per risolvere questo problema, compilare i file che includono Query.h senza l'opzione /permissive- .

  • Problema in um/cellularapi_oem.h

    Quando si usa l'opzione del /permissive- compilatore, la dichiarazione di inoltro di enum UICCDATASTOREACCESSMODE genera un avviso:

    typedef enum UICCDATASTOREACCESSMODE UICCDATASTOREACCESSMODE; // C4471
    

    La dichiarazione forward di un ambito è enum un'estensione Microsoft. Per risolvere questo problema, compilare i file che includono cellularapi_oem.h senza l'opzione /permissive- o usare l'opzione per disattivare l'avviso /wd C4471.

  • Problema in um/omscript.h

    In C++03, una conversione da un valore letterale stringa a BSTR (che è un typedef in wchar_t *) è deprecata ma consentita. In C++11 la conversione non è più consentita.

    virtual /* [id] */ HRESULT STDMETHODCALLTYPE setExpression(
         /* [in] */ __RPC__in BSTR propname,
         /* [in] */ __RPC__in BSTR expression,
         /* [in][defaultvalue] */ __RPC__in BSTR language = L"") = 0; // C2440
    

    Per risolvere questo problema, compilare i file che includono omscript.h senza l'opzione /permissive- o usare /Zc:strictStrings- invece.

Per impostare l'opzione del compilatore nell'ambiente di sviluppo di Visual Studio

In Visual Studio 2017 versione 15.5 e versioni successive usare questa procedura:

  1. Aprire la finestra di dialogo Pagine delle proprietà del progetto.

  2. Selezionare la pagina delle proprietà Proprietà>di configurazione C/C++>Language.

  3. Modificare il valore della proprietà Modalità conformità su Sì (/permissive-). Scegliere OK o Applica per salvare le modifiche.

Nelle versioni precedenti a Visual Studio 2017 versione 15.5 usare questa procedura:

  1. Aprire la finestra di dialogo Pagine delle proprietà del progetto.

  2. Selezionare la pagina delle proprietà Proprietà di configurazione>C/C++>Riga di comando.

  3. Immettere l'opzione del compilatore /permissive- nella casella Opzioni aggiuntive . Scegliere OK o Applica per salvare le modifiche.

Per impostare l'opzione del compilatore a livello di codice

Vedi anche

Opzioni del compilatore MSVC
Sintassi della riga di comando del compilatore MSVC