/permissive- (Zgodność ze standardami)

Określ tryb zgodności standardów z kompilatorem. Użyj tej opcji, aby ułatwić identyfikowanie i rozwiązywanie problemów ze zgodnością w kodzie, aby uczynić go bardziej poprawnym i bardziej przenośnym.

Składnia

/permissive-
/permissive

Uwagi

Opcja jest obsługiwana /permissive- w programie Visual Studio 2017 lub nowszym. /permissive program jest obsługiwany w programie Visual Studio 2019 w wersji 16.8 lub nowszej.

Możesz użyć opcji kompilatora /permissive- , aby określić zachowanie kompilatora zgodne ze standardami. Ta opcja wyłącza zachowania permisywne i ustawia opcje kompilatora pod kątem ścisłej /Zc zgodności. W środowisku IDE ta opcja sprawia również, że aparat IntelliSense podkreśla niezgodny kod.

Opcja /permissive- używa obsługi zgodności w bieżącej wersji kompilatora, aby określić, które konstrukcje języka są niezgodne. Opcja nie określa, czy kod jest zgodny z określoną wersją standardu C++. Aby włączyć całą zaimplementowaną obsługę kompilatora dla najnowszego standardu roboczego, użyj /std:c++latest opcji . Aby ograniczyć obsługę kompilatora do obecnie zaimplementowanego standardu C++20, użyj /std:c++20 opcji . Aby ograniczyć obsługę kompilatora do obecnie zaimplementowanego standardu /std:c++17 C++17, użyj opcji . Aby ograniczyć obsługę kompilatora w celu dokładniejszego dopasowania do standardu C++14, użyj /std:c++14 opcji , która jest domyślna.

Opcja /permissive- jest niejawnie ustawiana przez /std:c++latest opcję uruchamianą w programie Visual Studio 2019 w wersji 16.8 i w wersji 16.11 przez /std:c++20 opcję . /permissive- jest wymagany do obsługi modułów języka C++20. Być może twój kod nie wymaga obsługi modułów, ale wymaga innych funkcji włączonych w obszarze /std:c++20 lub /std:c++latest. Możesz jawnie włączyć obsługę rozszerzeń firmy Microsoft przy użyciu /permissive opcji bez końcowej kreski. Opcja /permissive musi pochodzić po każdej opcji, która ustawia /permissive- niejawnie.

Domyślnie /permissive- opcja jest ustawiana w nowych projektach utworzonych przez program Visual Studio 2017 w wersji 15.5 lub nowszej. Nie jest ona domyślnie ustawiana we wcześniejszych wersjach. Po ustawieniu opcji kompilator generuje błędy diagnostyczne lub ostrzeżenia, gdy w kodzie zostaną wykryte niestandardowe konstrukcje języka. Te konstrukcje obejmują niektóre typowe błędy w kodzie przed C++11.

Opcja /permissive- jest zgodna z prawie wszystkimi plikami nagłówków z najnowszych zestawów Windows Kit, takich jak zestaw Sdk (Software Development Kit) lub Zestaw Sterowników systemu Windows (WDK), począwszy od zestawu Windows Fall Creators SDK (10.0.16299.0). Starsze wersje zestawu SDK mogą nie zostać skompilowane z /permissive- różnych powodów zgodności kodu źródłowego. Kompilator i zestawy SDK są dostarczane na różnych osiach czasu wydania, więc istnieją pewne pozostałe problemy. Aby uzyskać informacje o konkretnych problemach z plikiem nagłówka, zobacz problemy z nagłówkami systemu Windows poniżej.

Opcja /permissive- ustawia /Zc:referenceBindingopcje , /Zc:strictStringsi /Zc:rvalueCast na zachowanie zgodne. Te opcje są domyślnie niezgodne z zachowaniem. Możesz przekazać określone /Zc opcje po /permissive- w wierszu polecenia, aby zastąpić to zachowanie.

W wersjach kompilatora rozpoczynających się w programie Visual Studio 2017 w wersji 15.3 /permissive- opcja ustawia /Zc:ternary tę opcję. Kompilator implementuje również więcej wymagań dotyczących wyszukiwania nazw dwufazowych. Po ustawieniu /permissive- opcji kompilator analizuje definicje funkcji i szablonów klas oraz identyfikuje nazwy zależne i nie zależne używane w szablonach. W tej wersji jest wykonywana tylko analiza zależności nazw.

Od programu Visual Studio 2022 Update 17.6 /permissive- opcja ustawia /Zc:lambda opcje i /Zc:externConstexpr . W poprzednich wersjach /permissive- nie ustawiono ani jednego.

Rozszerzenia specyficzne dla środowiska i obszary językowe, których standard pozostawia do implementacji, nie ma to wpływu na /permissive-element . Na przykład specyficzne dla __declspecfirmy Microsoft , wywoływanie konwencji i obsługi wyjątków strukturalnych, a dyrektywy lub atrybuty specyficzne dla pragma kompilatora nie są oflagowane przez kompilator w /permissive- trybie.

Kompilator MSVC we wcześniejszych wersjach programu Visual Studio 2017 nie obsługuje całego kodu zgodnego ze standardami języka C++11, C++14 ani C++17. W zależności od wersji programu Visual Studio /permissive- opcja może nie wykrywać problemów w niektórych aspektach wyszukiwania nazw dwufazowych, wiązania odwołania init tymczasowego, traktowania kopii jako bezpośredniego inicjowania, zezwalania na wiele konwersji zdefiniowanych przez użytkownika w inicjowaniu lub alternatywnych tokenów dla operatorów logicznych i innych nieobsługiwanych obszarów zgodności. Aby uzyskać więcej informacji na temat problemów ze zgodnością w programie Visual C++, zobacz Zachowanie niezgodne. Aby jak najlepiej /permissive-wykorzystać program , zaktualizuj program Visual Studio do najnowszej wersji.

Jak naprawić kod

Poniżej przedstawiono kilka przykładów kodu, który jest wykrywany jako niezgodny podczas korzystania z programu /permissive-, wraz z sugerowanymi sposobami rozwiązywania problemów.

Użyj default jako identyfikatora w kodzie natywnym

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

Wyszukiwanie elementów członkowskich w bazie zależnej

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();
}

Używanie kwalifikowanych nazw w deklaracjach składowych

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

Inicjowanie wielu członków unii w inicjatorze składowym

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;
};

Ukryte reguły wyszukiwania nazw znajomych

Deklaracja poza klasą może sprawić, że ukryty przyjaciel będzie widoczny:

// 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.

Użycie literału nullptr może uniemożliwić wyszukiwanie zależne od argumentów:

// 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.
}

Reguły wyszukiwania ukrytych nazw znajomych można włączyć niezależnie od /permissive polecenia ./Zc:hiddenFriend Jeśli chcesz używać starszego zachowania dla wyszukiwania ukrytej nazwy znajomego, ale w przeciwnym razie chcesz /permissive- zachowania, użyj /Zc:hiddenFriend- opcji .

Używanie wyliczenia o określonym zakresie w granicach tablicy

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.

Użyj dla każdego z nich w kodzie natywnym

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)
    {
        // ...
    }
}

Korzystanie z atrybutów ATL

Atrybuty ATL specyficzne dla firmy Microsoft mogą powodować problemy w obszarze /permissive-:

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

Problem można rozwiązać za pomocą __declspec formularza:

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

Bardziej złożony przykład:

// 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
{};

Rozwiązanie wymaga dodatkowych kroków kompilacji. W takim przypadku utwórz plik 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()
};

Niejednoznaczne argumenty operatorów warunkowych

W wersjach kompilatora przed programem Visual Studio 2017 w wersji 15.3 kompilator zaakceptował argumenty operatora warunkowego (lub operatoraternary), ?: które są uważane za niejednoznaczne przez standard. W /permissive- trybie kompilator wydaje teraz co najmniej jedną diagnostykę w przypadkach, które zostały skompilowane bez diagnostyki we wcześniejszych wersjach.

Typowe błędy, które mogą wynikać z tej zmiany, obejmują:

  • 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'

Typowy wzorzec kodu, który może spowodować ten problem, jest wtedy, gdy niektóre klasy C udostępniają zarówno konstruktor niejednoznaczny z innego typu T , jak i operator Tkonwersji niezwiązany z jawnym typem . Konwersja drugiego argumentu na typ trzeciego argumentu jest prawidłową konwersją. Tak więc jest konwersja trzeciego argumentu na typ drugiego argumentu. Ponieważ oba są prawidłowe, jest niejednoznaczny zgodnie ze standardem.

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

Istnieje ważny wyjątek dla tego wspólnego wzorca, gdy T reprezentuje jeden z typów ciągów zakończonych wartością null (na przykład const char *, const char16_t *, itd.), a rzeczywisty argument to ?: literał ciągu odpowiadającego mu typu. Język C++17 zmienił semantykę z języka C++14. W rezultacie kod w przykładzie 2 jest akceptowany w obszarze /std:c++14 i odrzucany w obszarze /std:c++17 lub nowszym, gdy /Zc:ternary jest /permissive- używany.

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

W operatorach warunkowych mogą być również widoczne błędy z jednym argumentem typu void. Ten przypadek może być typowy w makrach przypominających asertywne.

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

Mogą również wystąpić błędy w metaprogramowaniu szablonu, gdzie typy wyników operatora warunkowego mogą ulec zmianie w obszarze /Zc:ternary i /permissive-. Jednym ze sposobów rozwiązania tego problemu jest użycie std::remove_reference w typie wynikowym.

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

Wyszukiwanie nazwy dwufazowej

Po ustawieniu /permissive- opcji kompilator analizuje definicje funkcji i szablonów klas, identyfikując zależne i nie zależne nazwy używane w szablonach zgodnie z wymaganiami wyszukiwania nazw dwufazowych. W programie Visual Studio 2017 w wersji 15.3 wykonywana jest analiza zależności nazw. W szczególności nazwy niezależnych, które nie są deklarowane w kontekście definicji szablonu, powodują komunikat diagnostyczny zgodnie ze standardami ISO C++. W programie Visual Studio 2017 w wersji 15.7 jest również wykonywane powiązanie nazw niezależnych, które wymagają wyszukiwania zależnego od argumentów w kontekście definicji.

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

Jeśli chcesz używać starszego zachowania dla wyszukiwania dwufazowego, ale w przeciwnym razie chcesz /permissive- , dodaj /Zc:twoPhase- opcję.

Problemy z nagłówkami systemu Windows

Opcja jest zbyt ścisła /permissive- w przypadku wersji zestawów Windows Kit przed zestawem Windows Fall Creators Update SDK (10.0.16299.0) lub zestawem Windows Driver Kit (WDK) w wersji 1709. Zalecamy zaktualizowanie do najnowszych wersji zestawów windows do użycia /permissive- w kodzie systemu Windows lub sterownika urządzenia.

Niektóre pliki nagłówków w zestawie SDK aktualizacji systemu Windows April 2018 (10.0.17134.0), zestaw WINDOWS Fall Creators Update SDK (10.0.16299.0) lub zestaw Windows Driver Kit (WDK) 1709 nadal mają problemy, które sprawiają, że są niezgodne z użyciem /permissive-programu . Aby obejść te problemy, zalecamy ograniczenie używania tych nagłówków tylko do tych plików kodu źródłowego, które ich wymagają, i usunięcie /permissive- opcji podczas kompilowania tych określonych plików kodu źródłowego.

Te nagłówki biblioteki WinRT WRL wydane w zestawie Windows April 2018 Update SDK (10.0.17134.0) nie są czyste za pomocą polecenia /permissive-. Aby obejść te problemy, nie należy używać metody /permissive-lub używać jej /Zc:twoPhase-/permissive- podczas pracy z tymi nagłówkami:

  • Problemy w programie 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 w 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'
    

Te nagłówki trybu użytkownika wydane w zestawie SDK aktualizacji systemu Windows April 2018 (10.0.17134.0) nie są czyste przy użyciu polecenia /permissive-. Aby obejść te problemy, nie używaj /permissive- ich podczas pracy z tymi nagłówkami:

  • Problemy w programie 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 w 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
    
  • Problemy w programie 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'
    

Te problemy są specyficzne dla nagłówków trybu użytkownika w zestawie WINDOWS Fall Creators Update SDK (10.0.16299.0):

  • Problem w um/Query.h

    W przypadku korzystania z przełącznika /permissive- kompilatora tagRESTRICTION struktura nie kompiluje się ze względu na element case(RTOr) członkowski 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;
    };
    

    Aby rozwiązać ten problem, skompiluj pliki, które zawierają Query.h bez /permissive- opcji .

  • Problem w um/cellularapi_oem.h

    W przypadku korzystania z przełącznika /permissive- kompilatora deklaracja enum UICCDATASTOREACCESSMODE przekazywania powoduje ostrzeżenie:

    typedef enum UICCDATASTOREACCESSMODE UICCDATASTOREACCESSMODE; // C4471
    

    Przekazywanie deklaracji unscoped enum jest rozszerzeniem firmy Microsoft. Aby rozwiązać ten problem, skompiluj pliki, które zawierają cellularapi_oem.h bez /permissive- opcji, lub użyj /wd opcji, aby wyciszyć ostrzeżenie C4471.

  • Problem w um/omscript.h

    W języku C++03 konwersja z literału ciągu na BSTR (która jest definicją typu do wchar_t *) jest przestarzała, ale dozwolona. W języku C++11 konwersja nie jest już dozwolona.

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

    Aby rozwiązać ten problem, skompiluj pliki zawierające plik omscript.h bez /permissive- opcji lub użyj /Zc:strictStrings- zamiast tego.

Aby ustawić tę opcję kompilatora w środowisku programowania Visual Studio

W programie Visual Studio 2017 w wersji 15.5 lub nowszej użyj tej procedury:

  1. Otwórz okno dialogowe Strony właściwości projektu.

  2. Wybierz stronę właściwości Właściwości>konfiguracji C/C++>Language.

  3. Zmień wartość właściwości Trybu zgodności na Tak (/permissive-). Wybierz przycisk OK lub Zastosuj , aby zapisać zmiany.

W wersjach przed programem Visual Studio 2017 w wersji 15.5 użyj tej procedury:

  1. Otwórz okno dialogowe Strony właściwości projektu.

  2. Wybierz stronę Właściwości>konfiguracji C/C++>Wiersza polecenia.

  3. Wprowadź /permissive- kompilator opcji w polu Dodatkowe opcje. Wybierz przycisk OK lub Zastosuj , aby zapisać zmiany.

Aby programowo ustawić tę opcję kompilatora

Zobacz też

Opcje kompilatora MSVC
Składnia wiersza polecenia kompilatora MSVC