/permissive- (Übereinstimmung mit Standards)

Geben Sie den Standardkonformitätsmodus für den Compiler an. Verwenden Sie diese Option, um Konformitätsprobleme in Ihrem Code zu identifizieren und zu beheben, um sie sowohl korrekt als auch portierbarer zu machen.

Syntax

/permissive-
/permissive

Bemerkungen

Die /permissive- Option wird in Visual Studio 2017 und höher unterstützt. /permissivewird in Visual Studio 2019 Version 16.8 und höher unterstützt.

Sie können die /permissive- Compileroption verwenden, um standardskonformes Compilerverhalten anzugeben. Diese Option deaktiviert das verhaltende Verhalten und legt die /Zc Compileroptionen für strikte Konformität fest. In der IDE unterstreicht die IntelliSense-Engine mit dieser Option auch nicht konformen Code.

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 Option , um die gesamte implementierte Compilerunterstützung für den neuesten Standardentwurf zu /std:c++latest aktivieren. Verwenden Sie die Option , um die Compilerunterstützung auf den derzeit implementierten C++20-Standard zu /std:c++20 beschränken. Verwenden Sie die Option , um die Compilerunterstützung auf den derzeit implementierten C++17-Standard zu /std:c++17 beschränken. Um die Compilerunterstützung auf eine genauere Übereinstimmung mit dem C++14-Standard zu beschränken, verwenden Sie die /std:c++14 -Option, die die Standardeinstellung ist.

Die /permissive- Option wird implizit von der Option ab Visual Studio /std:c++latest 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 jedoch andere Features, die unter oder aktiviert /std:c++20/std:c++latest sind. Sie können die Microsoft-Erweiterungsunterstützung explizit aktivieren, indem Sie die /permissive Option ohne den nachgestellten Bindestrich verwenden.

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 im 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 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 unter möglicherweise nicht kompiliert /permissive- werden. Der Compiler und die SDKs werden auf verschiedenen Releasezeitplänen veröffentlicht, sodass noch einige Probleme auftreten. Spezifische Headerdateiprobleme finden Sie unter Windows Headerprobleme weiter unten.

Die /permissive- -Option legt die /Zc:referenceBinding Optionen , und auf das entsprechende Verhalten /Zc:strictStrings/Zc:rvalueCast fest. Diese Optionen sind standardmäßig nicht konform. Sie können bestimmte /Zc Optionen nach in der Befehlszeile /permissive- übergeben, um dieses Verhalten zu überschreiben.

In Versionen des Compilers ab Visual Studio 2017 Version 15.3 legt die /permissive- Option die /Zc:ternary Option fest. Der Compiler implementiert auch mehr anforderungen für die Zweiphasen-Namenssuche. Wenn die /permissive- Option festgelegt ist, 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 eine Namensabhängigkeitsanalyse ausgeführt.

Umgebungsspezifische Erweiterungen und Sprachbereiche, die der Standard der Implementierung überlässt, sind von nicht /permissive- betroffen. Beispielsweise werden die Microsoft-spezifischen __declspec Schlüsselwörter , Aufrufkonventionen und strukturierte Ausnahmebehandlung sowie compilerspezifische Pragmadirektiven oder Attribute nicht vom Compiler im /permissive- -Modus gekennzeichnet.

Nicht der gesamte C++11-, C++14- oder C++17-Standardcode wird vom MSVC Compiler in allen Versionen von Visual Studio 2017 unterstützt. Abhängig von der Version von Visual Studio erkennt die /permissive- Option möglicherweise keine Probleme in einigen Aspekten der zweistufigen Namenssuche, binden einen nicht const-Verweis auf einen temporären , behandelt copy init als direkten Initialisierungsvorgang, sodass mehrere benutzerdefinierte Konvertierungen bei der Initialisierung oder alternative Token für logische Operatoren und andere nicht unterstützte Konformitätsbereiche zulässig sind. Weitere Informationen über Konformitätsprobleme in Visual C++ finden Sie unter Nonstandard Behavior. Um das Beste aus zu /permissive- machen, aktualisieren Sie Visual Studio auf die neueste Version.

Beheben des Codes

Im Folgenden finden Sie einige Beispiele für Code, der bei Verwendung von als nicht konform erkannt /permissive- wird, zusammen mit vorgeschlagenen Möglichkeiten zum Beheben der Probleme.

Standard als Bezeichner in nativem Code verwenden

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

Suchen von Membern in einer abhängigen Basis

template <typename T>
struct B {
    void f();
};

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 is to uncomment the following line.
    // If this is a type, don't forget the 'typename' keyword.
    // using B<T>::f;

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

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

Verwenden von qualifizierten Namen in Memberdeklarationen

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

Initialisieren mehrerer Union-Member 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;
};

Suchregeln für ausgeblendete Friend-Namen

// 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.
// 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 Nachschlageregeln für ausgeblendete Friend-Namen unabhängig von /permissive mithilfe von /Zc:hiddenFriend aktivieren. Wenn Sie Legacyverhalten für die Suche nach ausgeblendeten Friend-Namen wünschen, aber andernfalls /permissive- Verhalten wünschen, verwenden Sie die /Zc:hiddenFriend- Option .

Verwenden bereichs begrenzter 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.

Verwenden sie für jede in nativem 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)
    {
        // ...
    }
}

Verwenden von ATL-Attributen

// Example 1
[uuid("594382D9-44B0-461A-8DE3-E06A3E73C5EB")]
class A {};
// Fix for example 1
class __declspec(uuid("594382D9-44B0-461A-8DE3-E06A3E73C5EB")) B {};
// 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
{};
// 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 hat der Compiler Argumente für den bedingten Operator (oder ternären Operator) ?: akzeptiert, die vom Standard als mehrdeutig betrachtet werden. Im /permissive- -Modus gibt der Compiler jetzt eine oder mehrere Diagnosen in Fällen aus, die in früheren Versionen ohne Diagnose kompiliert wurden.

Häufige Fehler, die sich aus dieser Änderung ergeben 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, ist, wenn einige Klasse C sowohl einen nicht expliziten Konstruktor von einem anderen Typ T als auch einen nicht expliziten Konvertierungsoperator zum Typ T bereitstellt. In diesem Fall sind sowohl die Konvertierung des zweiten Arguments in den Typ des dritten Arguments als auch die Konvertierung des dritten Arguments in den Typ des zweiten Arguments gültige Konvertierungen. Da beide gültig sind, ist sie gemäß 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 von diesem allgemeinen Muster, wenn T einen der mit NULL endenden Zeichenfolgentypen (z. B. const char * , usw.) darstellt und das tatsächliche Argument für ein const char16_t *?: Zeichenfolgenliteral des entsprechenden Typs ist. C++17 hat die Semantik von C++14 geändert. Daher wird der Code in Beispiel 2 unter akzeptiert /std:c++14 und unter oder höher /std:c++17 abgelehnt, wenn oder verwendet /Zc:ternary/permissive- wird.

// 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);

Ein weiterer Fall, in dem möglicherweise Fehler auftreten, sind bedingte Operatoren mit einem Argument vom Typ void . Dieser Fall kann in ASSERT-ähnlichen Makros häufig vorkommen.

// 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 bei der Vorlagenmetaprogrammierung angezeigt, bei denen sich die Ergebnistypen des bedingten Operators unter und ändern /Zc:ternary/permissive- können. 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

Nachschlagen von Namen in zwei Phasen

Wenn die /permissive- Option festgelegt ist, analysiert der Compiler Funktions- und Klassenvorlagendefinitionen und identifiziert abhängige und nicht abhängige Namen, die in Vorlagen verwendet werden, als für die Zweiphasen-Namenssuche erforderlich. In Visual Studio 2017 Version 15.3 wird eine Namensabhängigkeitsanalyse durchgeführt. Insbesondere nicht abhängige Namen, die nicht im Kontext einer Vorlagendefinition deklariert werden, verursachen eine Diagnosemeldung gemäß den ISO C++-Standards. In Visual Studio 2017 Version 15.7 wird auch die Bindung von nicht abhängigen Namen durchgeführt, 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 Legacyverhalten für die zweistufige Suche, aber andernfalls /permissive- Verhalten wünschen, fügen Sie die /Zc:twoPhase- Option hinzu.

Windows Headerprobleme

Die /permissive- Option ist für Versionen der Windows Kits vor Windows Fall Creators Update SDK (10.0.16299.0) oder version 1709 des Windows Driver Kit (WDK) zu streng. Es wird empfohlen, dass Sie ein Update auf die neuesten Versionen der Windows Kits durchführen, um /permissive- sie in Ihrem Windows- oder Gerätetreibercode zu verwenden.

Bei bestimmten Headerdateien im Update SDK Windows April 2018 (10.0.17134.0), im Windows Fall Creators Update SDK (10.0.16299.0) oder im Windows Driver Kit (WDK) 1709 liegen weiterhin Probleme vor, die sie mit der Verwendung von inkompatibel /permissive- machen. Um diese Probleme zu umgehen, empfiehlt es sich, die Verwendung dieser Header auf die Quellcodedateien zu beschränken, die sie benötigen, und die /permissive- Option zu entfernen, wenn Sie diese spezifischen Quellcodedateien kompilieren.

Diese WinRT-WRL-Header, die im Update-SDK Windows April 2018 (10.0.17134.0) veröffentlicht wurden, sind mit nicht /permissive- bereinigt. Um diese Probleme zu umgehen, verwenden Sie entweder nicht /permissive- , oder verwenden Sie mit , wenn Sie mit diesen /permissive-/Zc:twoPhase- Headern 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 Benutzermodusheader, die im Update SDK Windows April 2018 (10.0.17134.0) veröffentlicht wurden, sind mit nicht /permissive- bereinigt. Um diese Probleme zu umgehen, verwenden Sie /permissive- nicht, wenn Sie mit diesen Headern arbeiten:

  • 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/solldkhlp.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"

    Bei Verwendung des /permissive- Compilerschalters wird die tagRESTRICTION Struktur aufgrund des Case(RTOr)-Members "or" 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 Query.h ohne die /permissive- Option enthalten.

  • Problem in "um/cellularapi_oem.h"

    Bei Verwendung des /permissive- Compilerschalters löst die Vorwärtsdeklaration von enum UICCDATASTOREACCESSMODE eine Warnung aus:

    typedef enum UICCDATASTOREACCESSMODE UICCDATASTOREACCESSMODE; // C4471
    

    Die Vorwärtsdeklaration der nicht kopierten Enumeration ist eine Microsoft-Erweiterung. Um dieses Problem zu beheben, kompilieren Sie Dateien, die cellularapi_oem.h enthalten, ohne die /permissive- -Option, oder verwenden Sie die /wd -Option, um die Warnung C4471 stillzulegen.

  • Problem in "um/omscript.h"

    In C++03 ist eine Konvertierung von einem Zeichenfolgenliteral in BSTR (eine Typedef in "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 /Zc:strictStrings- Sie 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 Sie das Dialogfeld Eigenschaftenseiten Ihres Projekts.

  2. Wählen Sie die Eigenschaftenseite KonfigurationseigenschaftenC/C++-Sprache aus.

  3. Ändern Sie den Konformitätsmodus-Eigenschaftswert in Ja (/permissive-). Wählen Sie OK oder Übernehmen aus, um die Änderungen zu speichern.

Verwenden Sie in Versionen vor Visual Studio 2017 Version 15.5 dieses Verfahren:

  1. Öffnen Sie das Dialogfeld Eigenschaftenseiten Ihres Projekts.

  2. Klicken Sie auf der Eigenschaftenseite auf KonfigurationseigenschaftenC/C++Befehlszeile.

  3. Geben Sie die Compileroption /permissive- in das Feld Zusätzliche Optionen ein. Wählen Sie OK oder Übernehmen aus, um die Änderungen zu speichern.

So legen Sie diese Compileroption programmgesteuert fest

Siehe auch

MSVC-Compileroptionen
Syntax für die MSVC-Compilerbefehlszeile