/permissive-
(標準準拠)
コンパイラに標準準拠モードを指定します。 このオプションを使用すると、コード内の準拠の問題を特定して修正し、より正確で移植性の高いものにすることができます。
構文
/permissive-
/permissive
解説
/permissive-
オプションは Visual Studio 2017 以降でサポートされています。 /permissive
は、Visual Studio 2019 バージョン 16.8 以降でサポートされています。
/permissive-
コンパイラ オプションを使用して、標準に準拠したコンパイラの動作を指定できます。 このオプションは、制限のない動作を無効にし、厳格に準拠する /Zc
コンパイラ オプションを設定します。 IDE では、このオプションを使用すると、IntelliSense エンジンで非準拠コードに下線が引かれます。
/permissive-
オプションでは、現在のコンパイラ バージョンの準拠サポートを使用して、準拠していない言語コンストラクトが特定されます。 オプションでは、コードが C++ 標準の特定のバージョンに準拠しているかどうかは判断されません。 最新のドラフト標準に対して実装されているすべてのコンパイラ サポートを有効にするには、/std:c++latest
オプションを使用します。 コンパイラのサポートを現在実装されている C++20 標準に限定するには、/std:c++20
オプションを使用します。 コンパイラのサポートを現在実装されている C++17 標準に限定するには、/std:c++17
オプションを使用します。 コンパイラのサポートを C++14 標準に近いものになるよう制限するには、既定の /std:c++14
オプションを使用します。
/permissive-
オプションは、Visual Studio 2019 バージョン 16.8 以降では /std:c++latest
オプションで、バージョン 16.11 では /std:c++20
オプションで暗黙的に設定されます。 /permissive-
は C++20 モジュールをサポートするために必要です。 モジュールのサポートは必要ない可能性がありますが、/std:c++20
または /std:c++latest
で他の機能を有効にする必要があります。 末尾にダッシュを付けずに /permissive
オプションを使用して、Microsoft 拡張機能のサポートを明示的に有効にすることができます。 /permissive
オプションは、暗黙的に /permissive-
を設定するオプションの後に指定する必要があります。
既定では、/permissive-
オプションは Visual Studio 2017 バージョン 15.5 以降のバージョンで作成された新しいプロジェクトで設定されます。 以前のバージョンでは、既定では設定されません。 このオプションを設定すると、コードで非標準の言語コンストラクトが検出された場合に、コンパイラによって診断エラーまたは警告が生成されます。 これらのコンストラクトには、C++11 より前のコードでよくあるバグがいくつか含まれています。
/permissive-
オプションは、Windows Fall Creators SDK (10.0.16299.0) 以降、ソフトウェア開発キット (SDK) や Windows Driver Kit (WDK) などの最新 Windows キットのほとんどすべてのヘッダー ファイルと互換性があります。 ソース コードのさまざまな準拠の理由により、古いバージョンの SDK を /permissive-
でコンパイルできない場合があります。 コンパイラと SDK は異なるリリース タイムラインで出荷されるため、問題がいくつか残ります。 ヘッダー ファイルに関する具体的な問題については、以下の「Windows ヘッダーに関する問題」を参照してください。
/permissive-
オプションでは、/Zc:referenceBinding
、/Zc:strictStrings
、/Zc:rvalueCast
オプションが準拠した動作に設定されます。 これらのオプションは、既定で非準拠動作に設定されます。 コマンド ラインで /permissive-
の後に特定の /Zc
オプションを渡すことでこの動作をオーバーライドできます。
Visual Studio 2017 バージョン 15.3 以降のバージョンのコンパイラでは、/permissive-
オプションで /Zc:ternary
オプションが設定されます。 コンパイラには、2 フェーズの名前参照に関する要件の多くも実装されています。 /permissive-
オプションを設定すると、コンパイラでは、関数とクラスのテンプレート定義が解析され、テンプレートで使用される依存名と非依存名が識別されます。 このリリースでは、名前の依存関係の分析だけが実行されます。
Visual Studio 2022 Update 17.6 の時点で、 /permissive-
オプションは /Zc:lambda
オプションと /Zc:externConstexpr
オプションを設定します。 以前のバージョンでは、 /permissive-
はどちらも設定していませんでした。
標準で実装に委ねられる環境固有の拡張機能と言語領域は、/permissive-
による影響を受けません。 たとえば、Microsoft 固有の __declspec
、呼び出し規約、構造化例外処理のキーワード、コンパイラ固有の pragma
ディレクティブまたは属性は、/permissive-
モードでコンパイラによってフラグが設定されません。
以前のバージョンの Visual Studio 2017 の MSVC コンパイラで、すべての C++11、C++14、または C++17 標準に準拠するコードがサポートされているわけではありません。 Visual Studio のバージョンによっては、2 フェーズの名前参照、非 const 参照を一時的にバインドする場合、コピー初期化を直接初期化として扱う場合、初期化で複数のユーザー定義変換を行う場合、または、論理演算子の代替トークンおよびサポートされていないその他の準拠領域については、/permissive-
オプションで一部の問題が検出されない場合があります。 Visual C++ の準拠に関する問題について詳しくは、「 Nonstandard Behavior」をご覧ください。 /permissive-
を最大限活用するには、Visual Studio を最新バージョンに更新します。
コードを修正する方法
次に、/permissive-
を使用するときに非準拠として検出されるコードの例と、問題を解決するための推奨される方法を示します。
ネイティブ コードで識別子として default
を使用する
void func(int default); // Error C2321: 'default' is a keyword, and
// cannot be used in this context
依存ベースでメンバーを参照する
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();
}
メンバー宣言での修飾名を使用する
struct A {
void A::f() { } // error C4596: illegal qualified name in member
// declaration.
// Remove redundant 'A::' to fix.
};
メンバー初期化子内の複数の共用体メンバーを初期化する
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;
};
非表示のフレンド名の参照規則
クラス外の宣言では、非表示のフレンドを表示できます。
// 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.
リテラル nullptr
を使用すると、引数依存の参照を防ぐことができます。
// 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.
}
/Zc:hiddenFriend
を使用すると、/permissive
とは独立して、非表示のフレンド名の参照規則を有効にすることができます。 非表示のフレンド名参照に対して従来の動作が必要であるが、それ以外については /permissive-
動作が必要な場合は、/Zc:hiddenFriend-
オプションを使用します。
配列の範囲でスコープ列挙型を使用する
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.
ネイティブ コードで for each を使用する
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)
{
// ...
}
}
ATL 属性の使用
Microsoft 固有の ATL 属性は、 /permissive-
で問題を引き起こす可能性があります。
// Example 1
[uuid("594382D9-44B0-461A-8DE3-E06A3E73C5EB")]
class A {};
代わりに __declspec
フォームを使用して、この問題を解決できます。
// 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
{};
解決には、追加のビルド手順が必要です。 この場合は、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()
};
あいまいな条件演算子引数
Visual Studio 2017 バージョン 15.3 より前のバージョンのコンパイラは、標準であいまいと見なされる条件演算子 (または三項演算子) ?:
への引数を受け入れていました。 /permissive-
モードでは、以前のバージョンでは診断なしにコンパイルされたケースで、コンパイラから 1 つ以上の診断が発行されるようになりました。
この変更によって発生する可能性のある一般的なエラーは次のとおりです。
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'
この問題を引き起こす可能性がある一般的なコード パターンは、一部のクラス C
によって、別の型 T
からの非明示的なコンストラクターと、型 T
への非明示的な変換演算子の両方が提供されている場合です。 2 番目の引数から 3 番目の引数の型への変換は有効な変換です。 3 番目の引数から 2 番目の引数の型への変換も同じになります。 どちらも有効であるため、標準に基づくとあいまいです。
// 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;
T が null 値で終わる文字列型 (たとえば const char *
、const char16_t *
など) のいずれかを表し、?:
への実際の引数が対応する型の文字列リテラルである場合、この共通パターンには重要な例外があります。 C++17 では、C++14 からセマンティクスが変更されました。 その結果、/Zc:ternary
または /permissive-
が使用された場合、例 2 のコードは /std:c++14
では受け入れられ、/std:c++17
以降では拒否されます。
// 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);
型 void
の引数を 1 つ持つ条件演算子にエラーが表示されることがあります。 このケースは、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__))
また、テンプレート メタプログラミングにエラーが表示される場合もあります。この場合、条件演算子の結果の型が /Zc:ternary
と /permissive-
で変更される可能性があります。 この問題を解決する 1 つの方法は、結果の型で std::remove_reference
を使用することです。
// 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
2 フェーズの名前参照
/permissive-
オプションを設定すると、コンパイラでは、関数とクラスのテンプレート定義が解析され、2 フェーズの名前参照で必要となるテンプレートで使用される依存名と非依存名が識別されます。 Visual Studio 2017 バージョン 15.3 では、名前の依存関係の分析が実行されます。 特に、テンプレート定義のコンテキストで宣言されていない非依存の名前は、ISO C++ 標準で必要とされる診断メッセージを発生させます。 Visual Studio 2017 バージョン 15.7 では、定義コンテキストで引数依存の参照を必要とする非依存名のバインドも実行されます。
// 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();
}
2 フェーズの参照に対して従来の動作が必要であるが、それ以外については /permissive-
動作が必要な場合は、/Zc:twoPhase-
オプションを追加します。
Windows ヘッダーの問題
/permissive-
オプションは、Windows Fall Creators Update SDK (10.0.16299.0) または Windows Driver Kit (WDK) バージョン 1709 以前の Windows キットのバージョンに対して厳格すぎます。 Windows またはデバイス ドライバーで /permissive-
コードを使用するには、Windows キットの最新バージョンに更新することをお勧めします。
Windows April 2018 Update SDK (10.0.17134.0)、Windows Fall Creators Update SDK (10.0.16299.0)、Windows Driver Kit (WDK) 1709 の特定のヘッダー ファイルでは、/permissive-
の使用との互換性がなくなる問題が残っています。 これらの問題を回避するには、これらのヘッダーの使用を必要とするソース コード ファイルのみに制限し、それらの特定のソース コード ファイルをコンパイルするときに /permissive-
オプションを削除することをお勧めします。
Windows April 2018 Update SDK (10.0.17134.0) でリリースされたこれらの WinRT WRL ヘッダーは、/permissive-
に対してクリーンではありません。 これらの問題を回避するには、/permissive-
を使用しないか、これらのヘッダーを扱うときに /permissive-
と /Zc:twoPhase-
を使用します。
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
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'
Windows April 2018 Update SDK (10.0.17134.0) でリリースされたこれらのユーザー モード ヘッダーは /permissive-
に対してクリーンではありません。 これらの問題を回避するには、次のヘッダーを操作するときに /permissive-
を使用しないでください。
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
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
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'
これらの問題は、Windows Fall Creators Update SDK (10.0.16299.0) のユーザーモードヘッダーに固有のものです。
um/Query.h
の問題/permissive-
コンパイラ スイッチを使用する場合、tagRESTRICTION
構造体は、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; };
この問題に対処するには、
/permissive-
オプションを指定せずに、Query.h
を含むファイルをコンパイルします。um/cellularapi_oem.h
の問題/permissive-
コンパイラ スイッチを使用する場合、enum UICCDATASTOREACCESSMODE
の事前宣言によって警告が発生します。typedef enum UICCDATASTOREACCESSMODE UICCDATASTOREACCESSMODE; // C4471
対象範囲外の
enum
の事前宣言は Microsoft の拡張機能です。 この問題に対処するには、/permissive-
オプションを指定せずにcellularapi_oem.h
を含むファイルをコンパイルするか、/wd
オプションを使用して警告 C4471 をサイレント状態にします。um/omscript.h
の問題C++03 では、文字列リテラルから
BSTR
への変換 (wchar_t *
への typedef) は非推奨ですが、許可されます。 C++11 では、変換は許可されなくなりました。virtual /* [id] */ HRESULT STDMETHODCALLTYPE setExpression( /* [in] */ __RPC__in BSTR propname, /* [in] */ __RPC__in BSTR expression, /* [in][defaultvalue] */ __RPC__in BSTR language = L"") = 0; // C2440
この問題に対処するには、
/permissive-
オプションを指定せずに、omscript.h を含むファイルをコンパイルするか、代わりに/Zc:strictStrings-
を使用します。
Visual Studio 開発環境でこのコンパイラ オプションを設定するには
Visual Studio 2017 バージョン 15.5 以降のバージョンでは、次の手順を実行します。
プロジェクトの [プロパティ ページ] ダイアログ ボックスを開きます。
[構成プロパティ]>[C/C++]>[言語] プロパティ ページを選択します。
[準拠モード] プロパティ値を [はい (/permissive-)] に変更します。 [OK] または [適用] を選択して、変更内容を保存します。
Visual Studio 2017 バージョン 15.5 より前のバージョンの場合は、次の手順を実行します。
プロジェクトの [プロパティ ページ] ダイアログ ボックスを開きます。
[構成プロパティ]>[C/C++]>[コマンド ライン] プロパティ ページを選択します。
[追加のオプション] ボックスに /permissive- コンパイラ オプションを入力します。 [OK] または [適用] を選択して、変更内容を保存します。
このコンパイラ オプションをコードから設定するには
- 以下を参照してください。AdditionalOptions