Sdílet prostřednictvím


/permissive- (Shoda se standardy)

Zadejte režim souladu se standardy kompilátoru. Tato možnost vám pomůže identifikovat a opravit problémy s dodržováním předpisů v kódu, aby byla lépe správná i přenosnější.

Syntaxe

/permissive-
/permissive

Poznámky

Tato možnost je podporovaná /permissive- v sadě Visual Studio 2017 a novějších verzích. /permissive je podporován v sadě Visual Studio 2019 verze 16.8 a novější.

Pomocí možnosti kompilátoru můžete určit chování kompilátoru /permissive- odpovídající standardům. Tato možnost zakáže permisivní chování a nastaví možnosti kompilátoru /Zc pro striktní shodu. Tato možnost také v integrovaném vývojovém prostředí (IDE) podtrhuje modul IntelliSense nevyhovující kód.

Tato /permissive- možnost používá podporu shody v aktuální verzi kompilátoru k určení, které jazykové konstrukty nejsou v souladu. Tato možnost neurčuje, jestli váš kód odpovídá konkrétní verzi standardu C++. Pokud chcete povolit veškerou podporu implementovaného kompilátoru pro nejnovější standard konceptu, použijte tuto /std:c++latest možnost. Pokud chcete omezit podporu kompilátoru na aktuálně implementovaný standard C++20, použijte tuto /std:c++20 možnost. Pokud chcete omezit podporu kompilátoru na aktuálně implementovaný standard C++17, použijte tuto /std:c++17 možnost. Pokud chcete omezit podporu kompilátoru tak, aby lépe odpovídala standardu C++14, použijte /std:c++14 možnost, která je výchozí.

Možnost /permissive- je implicitně nastavena /std:c++latest možností počínaje sadou Visual Studio 2019 verze 16.8 a ve verzi 16.11 podle této /std:c++20 možnosti. /permissive- pro podporu modulů C++20 se vyžaduje. Váš kód možná nepotřebuje podporu modulů, ale vyžaduje jiné funkce povolené v /std:c++20 rámci nebo /std:c++latest. Podporu rozšíření Microsoftu můžete explicitně povolit pomocí /permissive možnosti bez koncové pomlčky. Tato /permissive možnost musí pocházet po všech možnostech, které se nastaví /permissive- implicitně.

Ve výchozím nastavení je tato /permissive- možnost nastavená v nových projektech vytvořených v sadě Visual Studio 2017 verze 15.5 a novějších verzích. Ve starších verzích není ve výchozím nastavení nastavená. Když je tato možnost nastavená, kompilátor vygeneruje diagnostické chyby nebo upozornění v případě, že jsou v kódu zjištěny nestandardní jazykové konstrukty. Tyto konstrukce zahrnují některé běžné chyby v kódu pre-C++11.

Tato /permissive- možnost je kompatibilní s téměř všemi soubory hlaviček z nejnovějších sad Windows Kit, jako je sada SDK (Software Development Kit) nebo Windows Driver Kit (WDK), počínaje sadou Windows Fall Creators SDK (10.0.16299.0). Starší verze sady SDK se nemusí zkompilovat /permissive- z různých důvodů souladu se zdrojovým kódem. Kompilátor a sady SDK se dodávají na různých časových osách vydaných verzí, takže existují některé zbývající problémy. Konkrétní problémy se souborem hlaviček najdete níže v hlavičce Windows.

Tato /permissive- možnost nastaví /Zc:referenceBindingchování /Zc:strictStrings, a /Zc:rvalueCast možnosti, aby odpovídaly chování. Tyto možnosti mají výchozí chování, které nevyhovuje. Po příkazovém řádku můžete předat konkrétní /Zc možnosti /permissive- , které toto chování přepíší.

Ve verzích kompilátoru začínajících v sadě Visual Studio 2017 verze 15.3 /permissive- nastaví možnost /Zc:ternary . Kompilátor také implementuje více požadavků pro dvoufázové vyhledávání názvů. Pokud je tato /permissive- možnost nastavená, kompilátor analyzuje definice funkcí a šablon tříd a identifikuje závislé a nespoléhací názvy použité v šablonách. V této verzi se provádí pouze analýza závislostí názvů.

Od verze Visual Studio 2022 Update 17.6 nastaví /permissive- /Zc:lambda možnost a /Zc:externConstexpr možnosti. V předchozích verzích /permissive- jste nenastavili ani jeden.

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

Kompilátor MSVC ve starších verzích sady Visual Studio 2017 nepodporuje veškerý kód odpovídající standardům C++11, C++14 nebo C++17. V závislosti na verzi sady Visual Studio nemusí tato /permissive- možnost detekovat problémy v některých aspektech dvoufázového vyhledávání názvů, vytvořit vazbu nekonfázového odkazu na dočasný, považovat inicializační inicializaci s kopírováním jako s přímým inicializací, povolit více uživatelsky definovaných převodů v inicializaci nebo alternativní tokeny pro logické operátory a další nepodporované oblasti shody. Další informace o problémech s shodami v jazyce Visual C++ naleznete v tématu Nestandardní chování. Pokud chcete získat maximum, /permissive-aktualizujte sadu Visual Studio na nejnovější verzi.

Jak opravit kód

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

Použití default jako identifikátor v nativním kódu

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

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

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

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í v inicializátoru člena

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

Skrytá pravidla vyhledávání jména přítele

Deklarace mimo třídu může zobrazit skrytého přítele:

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

Použití literálu nullptr může zabránit vyhledávání závislému na argumentu:

// 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 jmen přátel můžete povolit nezávisle /permissive na použití ./Zc:hiddenFriend Pokud chcete, aby vyhledávání skrytého jména přítele používalo starší verzi, ale jinak chcete /permissive- , použijte tuto /Zc:hiddenFriend- možnost.

Použití výčtů s vymezeným oborem v mezích pole

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

Atributy ATL specifické pro Microsoft můžou způsobovat problémy v části /permissive-:

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

Tento problém můžete vyřešit pomocí __declspec formuláře:

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

Složitější příklad:

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

Řešení vyžaduje další kroky sestavení. V tomto případě vytvořte soubor 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()
};

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

Ve verzích kompilátoru před sadou Visual Studio 2017 verze 15.3 kompilátor akceptoval argumenty podmíněného operátoru (nebo ternárního operátoru), ?: které jsou považovány za nejednoznačné podle standardu. V /permissive- režimu teď kompilátor vydává jednu nebo více diagnostik v případech, které byly zkompilovány bez diagnostiky v dřívějších verzích.

Mezi běžné chyby, které můžou vést k této změně, 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 způsobit tento problém je, když některá třída C poskytuje ne explicitní konstruktor z jiného typu T a non-explicitní převodní operátor na typ T. Převod druhého argumentu na typ třetího argumentu je platný převod. Proto je převod třetího argumentu na typ druhého argumentu. 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;

Existuje důležitá výjimka tohoto běžného vzoru, když T představuje jeden z typů řetězců ukončených hodnotou null (například const char *, const char16_t *atd.) a skutečný argument, který ?: má být řetězcový literál odpovídajícího typu. C++17 změnil sémantiku z C++14. V důsledku toho je kód v příkladu 2 přijat /std:c++14 a odmítnut v /std:c++17 rámci nebo později, pokud /Zc:ternary nebo /permissive- je použit.

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

V podmíněných operátorech se mohou zobrazit také chyby s jedním argumentem typu void. Tento případ může být běžný v makrech podobných 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í šablony se mohou zobrazit také chyby, ve kterých se můžou změnit /Zc:ternary typy výsledků podmíněného operátoru a /permissive-. Jedním ze způsobů, jak tento problém vyřešit, je použít std::remove_reference výsledný 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

Vyhledání dvoufázového názvu

Pokud je tato /permissive- možnost nastavená, kompilátor analyzuje definice funkcí a šablon tříd, identifikuje závislé a nespoléhající názvy používané v šablonách podle potřeby pro vyhledávání dvoufázových názvů. V sadě Visual Studio 2017 verze 15.3 se provádí analýza závislostí názvů. Zejména 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 sadě Visual Studio 2017 verze 15.7 se také provádí vazba nezávislosti na názvech, které vyžadují vyhledávání závislé na argumentech 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ší chování dvoufázového vyhledávání, ale jinak chcete, /permissive- přidejte /Zc:twoPhase- tuto možnost.

Problémy s hlavičkou Windows

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

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

Tyto hlavičky WRL winRT vydané v sadě Windows April 2018 Update SDK (10.0.17134.0) nejsou čisté /permissive-. Pokud chcete tyto problémy vyřešit, nepoužívejte /permissive-je nebo použijte /permissive- /Zc:twoPhase- při práci s těmito hlavičkami:

  • Problémy v 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 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 April 2018 Update SDK (10.0.17134.0) nejsou čisté /permissive-. Pokud chcete tyto problémy vyřešit, nepoužívejte /permissive- při práci 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/spddkhlp.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 sadě Windows Fall Creators Update SDK (10.0.16299.0):

  • Problém v um/Query.h

    Při použití přepínače kompilátoru /permissive- se tagRESTRICTION struktura nekompiluje kvůli členu case(RTOr) 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;
    };
    

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

  • Problém v um/cellularapi_oem.h

    Pokud použijete přepínač kompilátoru /permissive- , deklarace předávání enum UICCDATASTOREACCESSMODE způsobí upozornění:

    typedef enum UICCDATASTOREACCESSMODE UICCDATASTOREACCESSMODE; // C4471
    

    Forward deklarace bez rozsahu enum je rozšíření Microsoftu. Chcete-li tento problém vyřešit, zkompilujte soubory, které obsahují cellularapi_oem.h bez /permissive- možnosti, nebo použijte /wd možnost ticha upozornění C4471.

  • Problém v um/omscript.h

    V jazyce C++03 je převod z řetězcového literálu na BSTR (což je typedef na 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 /permissive- možnosti, nebo místo toho použijte /Zc:strictStrings- .

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

V sadě Visual Studio 2017 verze 15.5 a novějších verzích použijte tento postup:

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

  2. Vyberte stránku vlastností jazyka C/C++>Vlastnosti>konfigurace.

  3. Změňte hodnotu vlastnosti Režim shody na Ano (/permissive-). Změny uložíte kliknutím na OK nebo Použít .

Ve verzích před sadou Visual Studio 2017 verze 15.5 použijte tento postup:

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

  2. Vyberte stránku vlastností příkazového řádku C/C++>Vlastnosti>konfigurace.

  3. Do pole Další možnosti zadejte možnost /permissive- compiler. Změny uložíte kliknutím na OK nebo Použít .

Programové nastavení tohoto parametru kompilátoru

Viz také

Parametry kompilátoru MSVC
Syntaxe příkazového řádku kompilátoru MSVC