/permissive- (shoda se standardy)

Zadejte režim shody standardů s kompilátorem. Pomocí této možnosti můžete identifikovat a opravit problémy se shodou v kódu, aby byl správný i přenosnější.

Syntax

/permissive-
/permissive

Poznámky

Možnost /permissive- je podporovaná v Visual Studio 2017 a novějších verzích. /permissivese podporuje v Visual Studio 2019 verze 16.8 a novější.

Pomocí možnosti /permissive- kompilátoru můžete určit chování kompilátoru odpovídající standardům. Tato možnost zakáže permisivní chování a nastaví možnosti kompilátoru pro /Zc striktní shodu. V integrovaném vývojovém prostředí tato možnost také podečtení modulu IntelliSense nevyhovujícímu kódu.

Možnost používá podporu shody v aktuální verzi kompilátoru k určení, které jazykové konstrukce /permissive- neodpovídají. Možnost ne určuje, jestli váš kód odpovídá konkrétní verzi standardu C++. Pokud chcete povolit podporu všech implementované kompilátoru pro nejnovější koncept standardu, použijte /std:c++latest možnost . Pokud chcete omezit podporu kompilátoru na aktuálně implementované standardy C++20, použijte /std:c++20 možnost . Pokud chcete omezit podporu kompilátoru na aktuálně implementované standardy C++17, použijte /std:c++17 možnost . Pokud chcete omezit podporu kompilátoru tak, aby více odpovídala standardu C++14, použijte možnost /std:c++14 , která je výchozí.

Možnost se implicitně nastavuje pomocí možnosti /permissive-/std:c++latest počínaje Visual Studio 2019 verze 16.8 a ve verzi 16.11 pomocí /std:c++20 možnosti . /permissive- je vyžadován pro podporu modulů C++20. Váš kód možná nepotřebuje podporu modulů, ale vyžaduje další funkce povolené v rámci /std:c++20 nebo /std:c++latest . Podporu rozšíření Microsoftu můžete explicitně povolit pomocí možnosti /permissive bez koncového pomlčky.

Ve výchozím nastavení je tato možnost nastavená v nových projektech vytvořených /permissive- Visual Studio 2017 verze 15.5 a novější. V dřívějších verzích není ve výchozím nastavení nastavený. Když je tato možnost nastavená, kompilátor generuje diagnostické chyby nebo upozornění, když se v kódu detekují nestandardní jazykové konstrukce. Tyto konstrukce zahrnují některé běžné chyby v kódu před C++11.

Tato možnost je kompatibilní s téměř všemi soubory hlaviček z nejnovějších sad Windows, jako je sada SDK (Software Development Kit) nebo wdk (Windows Driver Kit), počínaje sadou /permissive- Windows Fall Creators SDK (10.0.16299.0). Starší verze sady SDK se nemusí pod z důvodu různé shody /permissive- se zdrojovým kódem zkompilovat. Kompilátor a verze SDK se dodá na různé časové osy vydání, takže existují některé zbývající problémy. Informace o konkrétních problémech se souborem hlaviček najdete Windows následujících potížích s hlavičkou.

Možnost /permissive- nastaví možnosti , a podle /Zc:referenceBinding/Zc:strictStrings/Zc:rvalueCast odpovídajícího chování. Tyto možnosti jsou ve výchozím nastavení nevyhovující chování. Toto chování můžete /Zc přepsat předáním konkrétních možností po na příkazovém /permissive- řádku.

Ve verzích kompilátoru počínaje verzí Visual Studio 2017 verze 15.3 nastaví /permissive- možnost /Zc:ternary . Kompilátor také implementuje více požadavků na dvoufázové vyhledávání názvů. Při nastavení možnosti kompilátor analyzuje definice funkcí a šablon tříd a identifikuje závislé a závislé názvy používané /permissive- v šablonách. V této verzi se provádí pouze analýza závislostí na názvu.

Rozšíření a oblasti jazyka specifické pro prostředí, které standard opustí až do implementace, nejsou ovlivněny /permissive- . Například specifické pro společnost Microsoft , konvence volání a klíčová slova zpracování strukturovaných výjimek a direktivy pragma nebo atributy specifické pro kompilátor nejsou kompilátorem v __declspec/permissive- režimu označeny.

Ne všechny kódy, které odpovídají standardům C++11, C++14 nebo C++17, kompilátor MSVC podporuje ve všech verzích Visual Studio 2017. V závislosti na verzi Visual Studio možnost nemusí detekovat problémy v některých aspektech dvoufázového vyhledávání názvů, svázání nesoučtového odkazu na dočasný objekt, zacházení s inicializací kopírování jako s přímým inicializací, což umožňuje více uživatelem definovaných převodů při inicializaci nebo alternativní tokeny pro logické operátory a další oblasti, které nepodporují /permissive- shodu. Další informace o problémech se shodou v Visual C++ najdete v tématu Nestandardní chování. Pokud chcete z nástroje získat co /permissive- nejvíce, aktualizujte Visual Studio na nejnovější verzi.

Jak opravit kód

Tady je několik příkladů kódu, který se při použití nástroje zjistil jako nevyhovující, společně s navrhovanými /permissive- způsoby, jak tyto problémy vyřešit.

Použití výchozího identifikátoru v nativním kódu

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

Vyhledávání členů v závislém základu

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

Použití kvalifikovaných názvů v deklaracích členů

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

Inicializace více členů sjednoceného v inicializátoru členu

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

Pravidla vyhledávání skrytých přátel

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

Pravidla vyhledávání skrytých přátel můžete povolit nezávisle na příkazu /permissive pomocí /Zc:hiddenFriend . Pokud chcete, aby se starší verze chování pro vyhledávání skrytých přátel, ale jinak chcete /permissive- chování, použijte /Zc:hiddenFriend- možnost .

Použití vymezených výčtů v mezích polí

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.

Použití pro každý v nativním kódu

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

Použití atributů ATL

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

Nejednoznačné argumenty podmíněného operátoru

Ve verzích kompilátoru před Visual Studio 2017 verze 15.3 kompilátor přijal argumenty podmíněného operátoru (nebo ternární operátor), které jsou standardem považovány za ?: nejednoznačné. V režimu teď kompilátor vydává jednu nebo více diagnostických případů, které se zkompilují /permissive- bez diagnostiky v dřívějších verzích.

Mezi běžné chyby, které mohou být výsledkem této změny, patří:

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

Typický vzor kódu, který může tento problém způsobit, je, když některá třída C poskytuje ne explicitní konstruktor z jiného typu T i operátor převodu, který není explicitní, na typ T. V tomto případě jsou převod druhého argumentu na typ třetího argumentu i převod třetího argumentu na typ druhého argumentu platné převody. Vzhledem k tomu, že obě jsou platné, je podle standardu nejednoznačné.

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

Tento běžný vzor má důležitou výjimku, když T představuje jeden z typů řetězců ukončených hodnotou null (například , atd.) a skutečný argument pro představuje řetězcový literál odpovídajícího const char *const char16_t *?: typu. C++17 změnil sémantiku z C++14. V důsledku toho je kód v příkladu 2 přijat v rámci a odmítnut v rámci nebo /std:c++14 později při použití nebo /std:c++17/Zc:ternary/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);

Dalším případem, kdy se vidíte chyby, je v podmíněných operátorech s jedním argumentem typu void . Tento případ může být běžný v makrech jako 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__))

V metaprogramování šablon se mohou zobrazit také chyby, kdy se v a mohou měnit typy výsledků podmíněného /Zc:ternary/permissive- operátoru. Jedním ze způsob, jak tento problém vyřešit, je std::remove_reference použít u výsledného typu.

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

Dvoufázové vyhledávání názvů

Při nastavení možnosti kompilátor analyzuje definice funkcí a šablon tříd a identifikuje závislé a závislé názvy používané v šablonách podle potřeby pro dvoufázové /permissive- vyhledávání názvů. V Visual Studio 2017 verze 15.3 se provádí analýza závislostí na názvu. Konkrétně nezávisející názvy, které nejsou deklarovány v kontextu definice šablony, způsobují diagnostickou zprávu podle požadavků standardů ISO C++. V Visual Studio 2017 verze 15.7 se také provádí vazba nesouvisející názvy, které vyžadují vyhledávání závislé na argumentu v kontextu definice.

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

Pokud chcete starší verzi chování pro dvoufázové vyhledávání, ale jinak chcete /permissive- chování, přidejte /Zc:twoPhase- možnost .

Windows s hlavičkou

Tato možnost je příliš striktní pro verze sad Windows Kit před /permissive- Windows Fall Creators Update SDK (10.0.16299.0) nebo wdk (Windows Driver Kit) verze 1709. Doporučujeme aktualizovat na nejnovější verze sad Windows Kit, abyste je mohli použít v Windows /permissive- kódu ovladače zařízení.

Některé soubory hlaviček v sadě Windows Update SDK z dubna 2018 (10.0.17134.0), sadě Windows Fall Creators Update SDK (10.0.16299.0) nebo sadě WDK (Windows Driver Kit) 1709 mají stále problémy, které je nekompatibilní s používáním /permissive- . Pokud chcete tyto problémy obvyřešit, doporučujeme omezit použití těchto hlaviček pouze na soubory zdrojového kódu, které je vyžadují, a odebrat možnost při kompilaci těchto konkrétních souborů /permissive- zdrojového kódu.

Tyto hlavičky WinRT WRL vydané v sadě sdk aktualizace Windows. dubna 2018 (10.0.17134.0) nejsou pomocí /permissive- čisté. Pokud chcete tyto problémy obvyřešit, při práci s těmito hlavičkami buď nepoužívejte , nebo použijte s /permissive-/permissive-/Zc:twoPhase- :

  • Problémy v souboru 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
    
  • Problém v souboru 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'
    

Tyto hlavičky uživatelského režimu vydané v sadě WINDOWS Update SDK z dubna 2018 (10.0.17134.0) nejsou pomocí /permissive- čisté. Pokud chcete tyto problémy obvyřešit, nepoužívejte při práci /permissive- s těmito hlavičkami:

  • Problémy v 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
    
  • Problém v um/spddštinalp.h

    C:\Program Files (x86)\Windows Kits\10\include\10.0.17134.0\um\spddkhlp.h(759): error C3861: 'pNode': identifier not found
    
  • Problémy v 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'
    

Tyto problémy jsou specifické pro hlavičky uživatelského režimu v Windows Fall Creators Update SDK (10.0.16299.0):

  • Problém v um/Query.h

    Při použití /permissive- přepínače kompilátoru se struktura nezkompiluje kvůli tagRESTRICTION členu case(RTOr) nebo.

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

    Pokud chcete tento problém vyřešit, zkompilujte soubory, které obsahují Query.h bez /permissive- možnosti .

  • Problém v um/cellularapi_oem.h

    Při použití /permissive- přepínače kompilátoru dopředná deklarace enum UICCDATASTOREACCESSMODE způsobí upozornění:

    typedef enum UICCDATASTOREACCESSMODE UICCDATASTOREACCESSMODE; // C4471
    

    Dopředná deklarace výčtu bez oborů je rozšíření společnosti Microsoft. Pokud chcete tento problém vyřešit, zkompilujte soubory, které zahrnují cellularapi_oem.h bez možnosti , nebo použijte možnost upozornění /permissive-/wd C4471.

  • Problém v um/omscript.h

    V jazyce C++03 je převod z řetězcového literálu na BSTR (což je definice typedef pro "wchar_t *") zastaralý, ale povolený. V jazyce C++11 už převod není povolený.

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

    Pokud chcete tento problém vyřešit, zkompilujte soubory, které obsahují omscript.h bez možnosti /permissive- , nebo použijte místo toho /Zc:strictStrings- .

Nastavení tohoto parametru kompilátoru ve vývojovém prostředí Visual Studio

v Visual Studio 2017 verze 15,5 a novější použijte tento postup:

  1. Otevřete dialogové okno stránky vlastností projektu.

  2. Vyberte stránku vlastností Konfiguracejazyka C/C++ .

  3. Změňte hodnotu vlastnosti Režim odpovídání na Ano (/Permissive-). Změny uložte kliknutím na OK nebo použít .

v části verze před Visual Studio 2017 verze 15,5 použijte tento postup:

  1. Otevřete dialogové okno stránky vlastností projektu.

  2. Vyberte stránku vlastností Konfiguracepříkazového řádku C/C++.

  3. Do pole Další možnosti zadejte možnost kompilátoru /Permissive- . Změny uložte kliknutím na OK nebo použít .

Programové nastavení tohoto parametru kompilátoru

Viz také

možnosti kompilátoru MSVC
MSVC syntaxe Command-Line kompilátoru