質問をすることでしか得られない、回答やアドバイスがある。

15分調べてもわからないことは、質問しよう!

新規登録して質問してみよう
ただいま回答率
85.31%
C++

C++はC言語をもとにしてつくられた最もよく使われるマルチパラダイムプログラミング言語の1つです。オブジェクト指向、ジェネリック、命令型など広く対応しており、多目的に使用されています。

Q&A

解決済

1回答

491閲覧

ある constexpr 関数のコンパイル可否が、コンパイラ毎に異なる。どのコンパイラの挙動がC++20仕様に準拠してるでしょう?

ButaDon

総合スコア6

C++

C++はC言語をもとにしてつくられた最もよく使われるマルチパラダイムプログラミング言語の1つです。オブジェクト指向、ジェネリック、命令型など広く対応しており、多目的に使用されています。

0グッド

0クリップ

投稿2023/10/28 08:36

編集2023/10/29 02:54

発生している問題・エラーメッセージ

下記コードのコンパイル可否の挙動が、MSVC と Clang で異なります。前者が NG、後者が OK です。
「 C++20の言語仕様の時点で、どちらの挙動が正しいか? 」を、明確に把握してる方がいらっしゃったら、是非伺えると幸いです。
どうぞよろしくお願いします。

該当のソースコード

c++11

1#include <cstdio> 2#include <cstdlib> 3 4// MSVC で NG だが、Clang で OK 5constexpr float operator ""_pi( const char* i_value ){ 6 // 上記 constexpr と 下記 strtof() の関係が問題。コンパイラにより、コンパイル可否の違いを生んでしまっている 7 return std::strtof( i_value, nullptr ) * 3.14159265f; 8} 9 10int main(){ 11 std::printf( "%f\n", 2_pi ); 12}

試したこと

下記の両コンパイラでコンパイルを試み、結果を確認した

補足情報(FW/ツールのバージョンなど)

試行したコンパイラ
Microsoft(R) C/C++ Optimizing Compiler Version 19.37.32825 for x86
Clang 16.0

気になる質問をクリップする

クリップした質問は、後からいつでもMYページで確認できます。

またクリップした質問に回答があった際、通知やメールを受け取ることができます。

バッドをするには、ログインかつ

こちらの条件を満たす必要があります。

guest

回答1

0

ベストアンサー

違反である (ill-formed) と考えます。

C++20 の項目で言えば 9.2.5.6 にある

For a constexpr function or constexpr constructor that is neither defaulted nor a template, if no argument values exist such that an invocation of the function or constructor could be an evaluated subexpression of a core constant expression, or, for a constructor, an evaluated subexpression of the initialization full-expression of some constant-initialized object, the program is ill-formed, no diagnostic required.

に引っかかります。

constexpr 関数はどんな入力に対しても定数を生成することがあり得ないような関数であってはならないというように読めます。 定数式が要求される文脈で関数が呼ばれるかどうかに関係なく constexpr 関数の定義に対する制限として記述されています。

また 16.5.5.7 では規格が constexpr であることを要求している以外のライブラリ関数が constexpr 関数として宣言されてはならないというような文言もあるので std::strtofconstexpr 関数であることはあり得ません。 故に質問の事例では constepxr 関数に対する要求を満たしていないと解釈できます。

ただ、診断不要 (no diagnostic required) とも書いてあるのでコンパイルが通る挙動が仕様に反しているというわけではないとも思います。

投稿2023/10/28 10:56

SaitoAtsushi

総合スコア5714

バッドをするには、ログインかつ

こちらの条件を満たす必要があります。

ButaDon

2023/11/05 11:26 編集

どうも有難うございます。 「 コンパイル不能にするのが望ましいが、出来たとしても仕様通りである 」と解釈致しました。もし誤解があり、かつお時間が許されるようでしたら、ご指摘頂けると大変幸いです。 不明瞭な仕様のように思え にわかに受容し難いですが、コンパイラを作る側の論理としてはそうせざるを得ない事情があるのだろう、と考える事に致します。
ButaDon

2023/10/28 16:04

すみません、誤記修正です。 誤:「 コンパイル不能にするのが望ましいが、出来てたとしても仕様通りである 」 正:「 コンパイル不能にするのが望ましいが、できたとしても仕様通りである 」
SaitoAtsushi

2023/10/29 01:38

その理解で正しいと思います。 かみ砕いて言えば constexpr に対する要求は「必ず定数を生成しなければならない」ではなく「定数を生成しうるものでなければならない」です。 仕様に例として書かれているコードを見てください。 constexpr int f(bool b) { return b ? throw 0 : 0; } // OK constexpr int f() { return f(true); } // ill-formed, no diagnostic required 入力によって成功したり失敗したりするようなものは違反ではありません。 あらゆる入力に対して必ず失敗するのが違反です。 もっと複雑なプログラムでも確実に失敗するときを必ず見抜かなければならない (成功する可能性があるならエラーにしてはならない) ということをコンパイラに対して要求するのは酷というものでしょう。 失敗がありうる関数でもよいのは、そうしないとあまりにも煩雑になりすぎるからです。 たとえば二乗を計算するだけのこんな関数でもオーバーフローの可能性はあり、オーバーフローした場合は定数式の要件を満たしません。 constexpr int square(int x) { return x*x; } かといってこの程度のものに範囲チェックをいちいち書くのも馬鹿らしいので失敗の「可能性がある」だけなら許すことにしているものと考えられます。 可能性があるだけなら許されますが実際に定数式の文脈での失敗は失敗として検出されるので心配なら適当なテストを書いておけばよいんじゃないでしょうか。 static_assert((int)2_pi); // static_assert の第一引数は定数式を要求する
ButaDon

2023/10/29 03:15

>あらゆる入力に対して必ず失敗するのが違反 なるほど。strtof() の例では、必ず即値化が不能(=失敗)だから、ill-formed(=違反)だと仰ったのですね。で ill-formed だとしても、その後の挙動はコンパイラに委ねる言語仕様だから、MSVC と Clang で差が出たと。 >心配なら適当なテストを書いておけばよい 確かに、こういう時の static_assert() ですね。 今回はこれを行う機会はありません。「 コンパイラ毎の挙動差が なぜ起こるか?を知りたかった だけ」だからです。 が、将来 必要が生じた時に思い出せるよう、明確に覚えておこうと思います。 捕捉して下さった情報は、私が知らなかった事や思いつけなかった事で、大変助かりました。 どうも有難うございました。
guest

あなたの回答

tips

太字

斜体

打ち消し線

見出し

引用テキストの挿入

コードの挿入

リンクの挿入

リストの挿入

番号リストの挿入

表の挿入

水平線の挿入

プレビュー

15分調べてもわからないことは
teratailで質問しよう!

ただいまの回答率
85.31%

質問をまとめることで
思考を整理して素早く解決

テンプレート機能で
簡単に質問をまとめる

質問する

関連した質問