/permissive-
(Standardskonformität)
Geben Sie den Standardkonformitätsmodus an den Compiler an. Verwenden Sie diese Option, um Kompatibilitätsprobleme in Ihrem Code zu identifizieren und zu beheben, um es sowohl korrekt als auch portierbarer zu machen.
Syntax
/permissive-
/permissive
Hinweise
Die /permissive-
Option wird in Visual Studio 2017 und höher unterstützt. /permissive
wird in Visual Studio 2019, Version 16.8 und höher, unterstützt.
Sie können die /permissive-
Compileroption verwenden, um das compilerkonforme Compilerverhalten anzugeben. Mit dieser Option werden zulässige Verhaltensweisen deaktiviert und die /Zc
Compileroptionen für strenge Konformität festgelegt. In der IDE wird mit dieser Option auch der IntelliSense-Modul nicht konformer Code unterstrichen.
Die /permissive-
Option verwendet die Konformitätsunterstützung in der aktuellen Compilerversion, um zu bestimmen, welche Sprachkonstrukte nicht konform sind. Die Option bestimmt nicht, ob Ihr Code einer bestimmten Version des C++-Standards entspricht. Verwenden Sie die /std:c++latest
Option, um alle implementierten Compilerunterstützung für den neuesten Entwurfsstandard zu aktivieren. Verwenden Sie die /std:c++20
Option, um die Compilerunterstützung auf den aktuell implementierten C++20-Standard einzuschränken. Verwenden Sie die /std:c++17
Option, um die Compilerunterstützung auf den aktuell implementierten C++17-Standard einzuschränken. Wenn Sie die Compilerunterstützung auf eine engere Übereinstimmung mit dem C++14-Standard beschränken möchten, verwenden Sie die /std:c++14
Option, bei der es sich um die Standardeinstellung handelt.
Die /permissive-
Option wird implizit von der /std:c++latest
Option ab Visual Studio 2019, Version 16.8, und in Version 16.11 durch die /std:c++20
Option festgelegt. /permissive-
ist für die Unterstützung von C++20-Modulen erforderlich. Möglicherweise benötigt Ihr Code keine Modulunterstützung, erfordert aber andere Features, die unter /std:c++20
oder /std:c++latest
. Sie können die Microsoft-Erweiterungsunterstützung explizit aktivieren, indem Sie die /permissive
Option ohne den nachfolgenden Gedankenstrich verwenden. Die /permissive
Option muss nach jeder Option kommen, die implizit festgelegt wird /permissive-
.
Standardmäßig wird die /permissive-
Option in neuen Projekten festgelegt, die von Visual Studio 2017, Version 15.5 und höher, erstellt wurden. Sie ist in früheren Versionen nicht standardmäßig festgelegt. Wenn die Option festgelegt ist, generiert der Compiler Diagnosefehler oder Warnungen, wenn nicht standardmäßige Sprachkonstrukte in Ihrem Code erkannt werden. Diese Konstrukte enthalten einige häufige Fehler im Code vor C++11.
Die /permissive-
Option ist mit fast allen Headerdateien aus den neuesten Windows Kits kompatibel, z. B. dem Software Development Kit (SDK) oder dem Windows Driver Kit (WDK), beginnend mit dem Windows Fall Creators SDK (10.0.16299.0). Ältere Versionen des SDK können aus verschiedenen Gründen der Quellcodekonformität möglicherweise nicht kompiliert werden /permissive-
. Der Compiler und die SDKs werden auf verschiedenen Releasezeitachsen ausgeliefert, daher gibt es noch einige Probleme. Spezifische Probleme mit Headerdateien finden Sie unter Windows-Headerprobleme unten.
Die /permissive-
Option legt das Verhalten des Verhaltens und der /Zc:referenceBinding
/Zc:strictStrings
Optionen fest/Zc:rvalueCast
. Diese Optionen sind standardmäßig nicht konformes Verhalten. Sie können bestimmte /Zc
Optionen nach /permissive-
der Befehlszeile übergeben, um dieses Verhalten außer Kraft zu setzen.
In Versionen des Compilers ab Visual Studio 2017, Version 15.3, legt die /permissive-
Option die /Zc:ternary
Option fest. Der Compiler implementiert auch weitere Anforderungen für die Zwei-Phasen-Namenssuche. Wenn die /permissive-
Option festgelegt wird, analysiert der Compiler Funktions- und Klassenvorlagendefinitionen und identifiziert abhängige und nicht abhängige Namen, die in den Vorlagen verwendet werden. In dieser Version wird nur die Namensabhängigkeitsanalyse durchgeführt.
Ab Visual Studio 2022 Update 17.6 legt die Option die /permissive-
/Zc:lambda
optionen fest /Zc:externConstexpr
. In früheren Versionen /permissive-
wurde keines festgelegt.
Umgebungsspezifische Erweiterungen und Sprachbereiche, die der Standard bei der Implementierung verlässt, sind nicht betroffen./permissive-
Beispielsweise werden die von Microsoft spezifischen __declspec
Aufrufkonventionen und die strukturierte Ausnahmebehandlungsstichwörter sowie compilerspezifische pragma
Direktiven oder Attribute nicht vom Compiler im /permissive-
Modus gekennzeichnet.
Der MSVC-Compiler in früheren Versionen von Visual Studio 2017 unterstützt nicht alle C++11-, C++14- oder C++17-standardskonformen Code. Abhängig von der Version von Visual Studio erkennt die /permissive-
Option möglicherweise keine Probleme in einigen Aspekten der zweistufigen Namenssuche, binden sie einen Nichtkonstverweis auf einen temporären Verweis, behandeln kopierinit als direktes Init, zulassen mehrerer benutzerdefinierter Konvertierungen in der Initialisierung oder alternative Token für logische Operatoren und andere nicht unterstützte Konformitätsbereiche. Weitere Informationen über Konformitätsprobleme in Visual C++ finden Sie unter Nonstandard Behavior. Um visual Studio optimal zu /permissive-
verwenden, aktualisieren Sie Visual Studio auf die neueste Version.
Beheben des Codes
Im Folgenden finden Sie einige Beispiele für Code, der bei Verwendung /permissive-
als nicht konform erkannt wird, zusammen mit vorgeschlagenen Methoden zum Beheben der Probleme.
Verwenden default
als Bezeichner im systemeigenen Code
void func(int default); // Error C2321: 'default' is a keyword, and
// cannot be used in this context
Nachschlagen von Mitgliedern in abhängiger Basis
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();
}
Verwendung qualifizierter Namen in Memberdeklarationen
struct A {
void A::f() { } // error C4596: illegal qualified name in member
// declaration.
// Remove redundant 'A::' to fix.
};
Initialisieren mehrerer Union-Mitglieder in einem Memberinitialisierer
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;
};
Nachschlageregeln für ausgeblendete Freunde
Eine Deklaration außerhalb eines Kurses kann einen verborgenen Freund sichtbar machen:
// 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.
Die Verwendung von Literal nullptr
kann argumentabhängige Suche verhindern:
// 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.
}
Sie können die Suchregeln für ausgeblendete Freundesnamen unabhängig von /permissive
der Verwendung /Zc:hiddenFriend
aktivieren. Wenn Sie ein Legacyverhalten für die Suche nach ausgeblendeten Freundnamen wünschen, andernfalls aber verhalten möchten /permissive-
, verwenden Sie die /Zc:hiddenFriend-
Option.
Verwenden von bereichsbezogenen Enumerationen in Arraygrenzen
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.
Verwendung für jeden in systemeigenem Code
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)
{
// ...
}
}
Verwendung von ATL-Attributen
Microsoft-spezifische ATL-Attribute können Probleme verursachen unter /permissive-
:
// Example 1
[uuid("594382D9-44B0-461A-8DE3-E06A3E73C5EB")]
class A {};
Sie können das Problem mithilfe des Formulars __declspec
beheben:
// Fix for example 1
class __declspec(uuid("594382D9-44B0-461A-8DE3-E06A3E73C5EB")) B {};
Ein komplexeres Beispiel:
// 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
{};
Für die Lösung sind zusätzliche Buildschritte erforderlich. Erstellen Sie in diesem Fall eine IDL-Datei:
// 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()
};
Mehrdeutige bedingte Operatorargumente
In Versionen des Compilers vor Visual Studio 2017, Version 15.3, akzeptierte der Compiler Argumente für den bedingten Operator (oder den ternären Operator), ?:
die vom Standard als mehrdeutig betrachtet werden. Im /permissive-
Modus gibt der Compiler jetzt eine oder mehrere Diagnosen in Fällen aus, die ohne Diagnose in früheren Versionen kompiliert wurden.
Häufige Fehler, die aus dieser Änderung resultieren können, sind:
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'
Ein typisches Codemuster, das dieses Problem verursachen kann, besteht darin, dass einige Klassen C
sowohl einen nicht expliziten Konstruktor eines anderen Typs T
als auch einen nicht expliziten Konvertierungsoperator zum Typ T
bereitstellt. Die Konvertierung des zweiten Arguments in den Typ des dritten Arguments ist eine gültige Konvertierung. Dies ist die Konvertierung des dritten Arguments in den Typ des zweiten Arguments. Da beide gültig sind, ist es nach dem Standard mehrdeutig.
// 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;
Es gibt eine wichtige Ausnahme für dieses allgemeine Muster, wenn T einen der null-beendeten Zeichenfolgentypen (z const char *
. B. , const char16_t *
usw.) darstellt und das tatsächliche Argument ?:
ein Zeichenfolgenliteral des entsprechenden Typs ist. C++17 hat die Semantik von C++14 geändert. Daher wird der Code in Beispiel 2 bei Verwendung oder später unter /std:c++14
/std:c++17
oder höher /Zc:ternary
/permissive-
akzeptiert und abgelehnt.
// 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);
Möglicherweise werden auch Fehler in bedingten Operatoren mit einem Argument vom Typ void
angezeigt. Dieser Fall kann in ASSERT-ähnlichen Makros üblich sein.
// 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__))
Möglicherweise werden auch Fehler in der Vorlagenmetaprogrammierung angezeigt, bei denen sich die Ergebnistypen des bedingten Operators unter und /permissive-
./Zc:ternary
Eine Möglichkeit, dieses Problem zu beheben, ist die Verwendung std::remove_reference
für den resultierenden Typ.
// 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
Zweistufiger Nachschlagename
Wenn die /permissive-
Option festgelegt ist, analysiert der Compiler Funktions- und Klassenvorlagendefinitionen, identifiziert abhängige und nicht abhängige Namen, die in Vorlagen verwendet werden, wie für die Suche nach zwei Phasennamen erforderlich. In Visual Studio 2017, Version 15.3, wird die Namensabhängigkeitsanalyse ausgeführt. Insbesondere verursachen nicht abhängige Namen, die nicht im Kontext einer Vorlagendefinition deklariert sind, eine Diagnosemeldung gemäß den ISO-C++-Standards. In Visual Studio 2017, Version 15.7, erfolgt auch die Bindung nicht abhängiger Namen, die eine argumentabhängige Suche im Definitionskontext erfordern.
// 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();
}
Wenn Sie ein Legacyverhalten für die Zwei-Phasen-Suche wünschen, andernfalls verhalten möchten /permissive-
, fügen Sie die /Zc:twoPhase-
Option hinzu.
Probleme mit Windows-Headern
Die /permissive-
Option ist für Versionen von Windows Kits vor Windows Fall Creators Update SDK (10.0.16299.0) oder dem Windows Driver Kit (WDK) Version 1709 zu streng. Es wird empfohlen, auf die neuesten Versionen der Windows Kits zu aktualisieren, die in Ihrem Windows- oder Gerätetreibercode verwendet werden /permissive-
sollen.
Bestimmte Headerdateien im Windows April 2018 Update SDK (10.0.17134.0), das Windows Fall Creators Update SDK (10.0.16299.0) oder das Windows Driver Kit (WDK) 1709 weisen weiterhin Probleme auf, die sie mit der Verwendung /permissive-
inkompatibel machen. Um diese Probleme zu umgehen, empfiehlt es sich, die Verwendung dieser Header auf die Quellcodedateien zu beschränken, die sie erfordern, und die /permissive-
Option beim Kompilieren dieser spezifischen Quellcodedateien zu entfernen.
Diese WinRT WRL-Header, die im Windows April 2018 Update SDK (10.0.17134.0) veröffentlicht wurden, sind nicht sauber mit /permissive-
. Um diese Probleme zu umgehen, verwenden /permissive-
Sie entweder nicht, oder verwenden /permissive-
/Zc:twoPhase-
Sie diese, wenn Sie mit diesen Kopfzeilen arbeiten:
Probleme 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
Problem 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'
Diese im Windows April 2018 Update SDK (10.0.17134.0) veröffentlichten Benutzermodusheader sind nicht sauber./permissive-
Um diese Probleme zu umgehen, verwenden /permissive-
Sie beim Arbeiten mit diesen Headern nicht:
Probleme 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
Problem 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
Probleme 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'
Diese Probleme gelten speziell für Benutzermodusheader im Windows Fall Creators Update SDK (10.0.16299.0):
Problem in
um/Query.h
Wenn Sie den
/permissive-
Compilerschalter verwenden, wird dietagRESTRICTION
Struktur aufgrund descase(RTOr)
Elementsor
nicht kompiliert.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; };
Um dieses Problem zu beheben, kompilieren Sie Dateien, die ohne die
/permissive-
Option enthaltenQuery.h
sind.Problem in
um/cellularapi_oem.h
Wenn Sie den
/permissive-
Compilerschalter verwenden, bewirkt die Weiterleitungsdeklarationenum UICCDATASTOREACCESSMODE
eine Warnung:typedef enum UICCDATASTOREACCESSMODE UICCDATASTOREACCESSMODE; // C4471
Die Weiterleitungsdeklaration einer nicht bereichsorientierten
enum
Deklaration ist eine Microsoft-Erweiterung. Um dieses Problem zu beheben, kompilieren Sie Dateien, die ohne die/permissive-
Option enthaltencellularapi_oem.h
sind, oder verwenden Sie die Option zum Stillen der/wd
Warnung C4471.Problem in
um/omscript.h
In C++03 ist eine Konvertierung von einem Zeichenfolgenliteral in (ein Typedef in
BSTR
wchar_t *
) veraltet, aber zulässig. In C++11 ist die Konvertierung nicht mehr zulässig.virtual /* [id] */ HRESULT STDMETHODCALLTYPE setExpression( /* [in] */ __RPC__in BSTR propname, /* [in] */ __RPC__in BSTR expression, /* [in][defaultvalue] */ __RPC__in BSTR language = L"") = 0; // C2440
Um dieses Problem zu beheben, kompilieren Sie Dateien, die omscript.h ohne die
/permissive-
Option enthalten, oder verwenden Sie/Zc:strictStrings-
stattdessen.
So legen Sie diese Compileroption in der Visual Studio-Entwicklungsumgebung fest
Verwenden Sie in Visual Studio 2017, Version 15.5 und höher, dieses Verfahren:
Öffnen Des Dialogfelds "Eigenschaftenseiten " des Projekts.
Navigieren Sie zur Eigenschaftenseite Konfigurationseigenschaften>C/C++>Sprache.
Ändern Sie den Eigenschaftswert des Konformitätsmodus in Ja (/zulässig-). Wählen Sie OK oder Übernehmen, um die Änderungen zu speichern.
Verwenden Sie in Versionen vor Visual Studio 2017, Version 15.5, dieses Verfahren:
Öffnen Des Dialogfelds "Eigenschaftenseiten " des Projekts.
Klicken Sie auf der Eigenschaftenseite auf Konfigurationseigenschaften>C/C++>Befehlszeile.
Geben Sie die Option "/permissive-compiler" in das Feld "Zusätzliche Optionen " ein. Wählen Sie OK oder Übernehmen, um die Änderungen zu speichern.
So legen Sie diese Compileroption programmgesteuert fest
- Siehe AdditionalOptions.
Siehe auch
MSVC-Compileroptionen
Syntax für die MSVC-Compilerbefehlszeile