/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:referenceBinding
opzioni , /Zc:strictStrings
e /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 __declspec
pragma
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, latagRESTRICTION
struttura non viene compilata a causa delcase(RTOr)
membroor
.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 dienum 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 includonocellularapi_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 inwchar_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:
Aprire la finestra di dialogo Pagine delle proprietà del progetto.
Selezionare la pagina delle proprietà Proprietà>di configurazione C/C++>Language.
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:
Aprire la finestra di dialogo Pagine delle proprietà del progetto.
Selezionare la pagina delle proprietà Proprietà di configurazione>C/C++>Riga di comando.
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
- Vedere AdditionalOptions.
Vedi anche
Opzioni del compilatore MSVC
Sintassi della riga di comando del compilatore MSVC