これは有効なC++ですか?
_int main() {
constexpr auto sz = __func__ - __func__;
return sz;
}
_
GCCとMSVCは問題ないと考えていますが、Clangは問題があると考えています: Compiler Explorer 。
すべてのコンパイラは、これが問題ないことを認めています: Compiler Explorer 。
_int main() {
constexpr auto p = __func__;
constexpr auto p2 = p;
constexpr auto sz = p2 - p;
return sz;
}
_
Clangはこれも好きではありませんが、他のものは問題ありません。 Compiler Explorer
_int main() {
constexpr auto p = __func__;
constexpr auto p2 = __func__;
constexpr auto sz = p2 - p;
return sz;
}
_
ここは何ですか?無関係なポインタの算術は未定義の動作だと思いますが、___func__
_は同じポインタを返しますか?わからないので、テストしてみようかなと思いました。私が正しく思い出せば、_std::equal_to
_は未定義の動作なしに無関係なポインタを比較できます。
_#include <functional>
int main() {
constexpr std::equal_to<const char*> eq{};
static_assert(eq(__func__, __func__));
}
_
Clangは、eq(__func__, __func__)
is constexpr であっても、std::equal_to::operator()
は定数式ではないと考えています。他のコンパイラは文句を言わない: Compiler Explorer
Clangはこれもコンパイルしません。 ___func__ == __func__
_が定数式ではないと不平を言う: Compiler Explorer
_int main() {
static_assert(__func__ == __func__);
}
_
C++の__func__
は識別子です。特に、特定のオブジェクトを参照します。 From [dcl.fct.def.general]/8 :
関数ローカルの事前定義変数
__func__
は、フォームの定義のように定義されますstatic const char __func__[] = "function-name";
function-nameは実装定義の文字列です。そのような変数がプログラム内の他のオブジェクトのアドレスとは異なるアドレスを持っているかどうかは指定されていません。
function-local事前定義変数 として、この定義は(まるで)関数ブロックの先頭に表示されます。そのため、そのブロック内で__func__
を使用すると、その変数が参照されます。
「その他のオブジェクト」の部分と同様に、変数はオブジェクトを定義します。 __func__
は、その変数によって定義されたオブジェクトに名前を付けます。したがって、関数内では、__func__
をすべて使用すると同じ変数に名前が付けられます。 variableが他のオブジェクトとは異なるオブジェクトであるかどうかは未定義です。
つまり、foo
という名前の関数で、リテラル"foo"
を問題の別の場所で使用した場合、実装が変数__func__
を持つことは禁止されていませんまた、リテラル"foo"
が返すオブジェクトと同じです。つまり、標準では、__func__
が出現するすべての関数が文字列リテラル自体とは別にデータを格納する必要はありません。
現在、C++の「あたかも」ルールは、実装がこれから逸脱することを許可していますが、それらは検出できない方法でそれを行うことはできません。したがって、変数自体が他のオブジェクトと異なるアドレスを持っている場合と持っていない場合がありますが、同じ関数での__func__
の使用は、同じオブジェクトを参照しているかのように動作する必要があります。
Clangはこのように__func__
を実装していないようです。関数名のprvalue文字列リテラルを返すかのように実装しているようです。 2つの異なる文字列リテラルは同じオブジェクトを参照する必要がないため、それらへのポインターを減算するとUBになります。また、定数式のコンテキストでの未定義の動作は不正です。
ここでClangが100%間違っていると言うのをためらっている唯一のことは [temp.arg.nontype]/2 です。
参照型またはポインタ型の非型テンプレートパラメータの場合、定数式の値は参照されません(またはポインタ型の場合、アドレスにならない)。
...
- 定義済みの
__func__
変数。
参照してください、これは実装によるいくつかの曖昧さを許容するようです。つまり、__func__
は技術的には定数式にすることができますが、テンプレートパラメータでは使用できません。技術的には変数ですが、文字列リテラルのように扱われます。
したがって、あるレベルでは、標準は口の両側から話していると言えます。