/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:strictStringsOptionen 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 __declspecAufrufkonventionen 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:hiddenFriendaktivieren. 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 Tbereitstellt. 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 voidangezeigt. 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 die tagRESTRICTION Struktur aufgrund des case(RTOr) Elements ornicht 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 enthalten Query.h sind.

  • Problem in um/cellularapi_oem.h

    Wenn Sie den /permissive- Compilerschalter verwenden, bewirkt die Weiterleitungsdeklaration enum 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 enthalten cellularapi_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:

  1. Öffnen Des Dialogfelds "Eigenschaftenseiten " des Projekts.

  2. Navigieren Sie zur Eigenschaftenseite Konfigurationseigenschaften>C/C++>Sprache.

  3. Ä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:

  1. Öffnen Des Dialogfelds "Eigenschaftenseiten " des Projekts.

  2. Klicken Sie auf der Eigenschaftenseite auf Konfigurationseigenschaften>C/C++>Befehlszeile.

  3. 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 auch

MSVC-Compileroptionen
Syntax für die MSVC-Compilerbefehlszeile