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

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

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

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

解決済

constexpr if と local struct の評価のタイミングについて

alphya
alphya

総合スコア124

C++

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

3回答

1グッド

1クリップ

2541閲覧

投稿2018/12/28 20:39

編集2018/12/30 10:53

#constexpr if と local struct の評価のタイミングについて
こんにちは!またよろしくお願いします!
ペコリ(o_ _)o))

初めに、次のコードはコンパイルエラーになります。case: 1
wandbox

cpp

1#include <type_traits> 2 3struct S { 4 constexpr auto operator()() const -> decltype(false) { 5 return false; 6 } 7}; 8 9template<typename T> 10constexpr T get() { 11 if constexpr (std::is_same_v<int, T>) return 0; 12 else static_assert(S{}(), "Lambda expression is evaluated."); 13} 14 15int main() { 16 get<int>(); 17}

つぎに、これはコンパイルが通ります。case: 2
wandbox

cpp

1#include <type_traits> 2 3template<typename T> 4constexpr T get() { 5 struct S { 6 constexpr auto operator()() const -> decltype(false) { 7 return false; 8 } 9 }; 10 if constexpr (std::is_same_v<int, T>) return 0; 11 else static_assert(S{}(), "Lambda expression is evaluated."); 12} 13 14int main() { 15 get<int>(); 16}

質問1: case: 2 の S{}() は、get()が定義される際になぜ評価されないのでしょうか。local struct S はテンプレートではないので、インスタンス化を抑制するconstexpr ifは関係なく、case: 1 と同様に評価されるのではないでしょうか...? それとも、local struct S はテンプレート引数Tに依存しているのでしょうか...

質問2: constexpr ifとtwo-phase name lookupは関係があったのでしょうか。ずっとそう思っていたのですが、constexpr ifは"テンプレート引数に依存しているものの実体化を遅延する"と考えると、名前の検索のタイミングは関係ないような気がします...。
(追記)
質問2に関して、インスタンス化されていないテンプレートはそもそも使えないので、テンプレート定義の中に依存名があってもなくても同じと考えられないでしょうか。

(追記の追記) すみません...質問2はなかったことにしてください...

yohhoy👍を押しています

以下のような質問にはグッドを送りましょう

  • 質問内容が明確
  • 自分も答えを知りたい
  • 質問者以外のユーザにも役立つ

グッドが多くついた質問は、TOPページの「注目」タブのフィードに表示されやすくなります。

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

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

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

下記のような質問は推奨されていません。

  • 間違っている
  • 質問になっていない投稿
  • スパムや攻撃的な表現を用いた投稿

適切な質問に修正を依頼しましょう。

回答3

1

質問1: (略)それとも、local struct S はテンプレート引数Tに依存しているのでしょうか...

テンプレート関数に含まれるローカルクラス(およびローカル構造体)は依存名(dependent name)とみなす仕様となっています。関連する話題として CWG#1484 Unused local classes of function templates があり、C++17言語仕様 §17.7.1 Implicit instantiation [temp.inst], Paragraph 1 には下記ノートが記載されています。

[Note: Within a template declaration, a local class (12.4) or enumeration and the members of a local class are never considered to be entities that can be separately instantiated (this includes their default arguments, noexcept-specifiers, and non-static data member initializers, if any). As a result, the dependent names are looked up, the semantic constraints are checked, and any templates used are instantiated as part of the instantiation of the entity within which the local class or enumeration is declared. -- end note]


質問2: constexpr ifとtwo-phase name lookupは関係があったのでしょうか。ずっとそう思っていたのですが、constexpr ifは"テンプレート引数に依存しているものの実体化を遅延する"と考えると、名前の検索のタイミングは関係ないような気がします...。

(質問意図を正確にくみとれていませんが)constexpr ifにより制御される文(=ifのthen/else節)のいずれがインスタンス化されるかが、同ifの条件部定数式によって決まります。two-phase name lookupとの関連でいえば、1回目の非依存名に関する探索はthen/else節の両者で行われます。

投稿2018/12/29 09:51

編集2018/12/29 10:09
yohhoy

総合スコア6177

alphya👍を押しています

良いと思った回答にはグッドを送りましょう。
グッドが多くついた回答ほどページの上位に表示されるので、他の人が素晴らしい回答を見つけやすくなります。

下記のような回答は推奨されていません。

  • 間違っている回答
  • 質問の回答になっていない投稿
  • スパムや攻撃的な表現を用いた投稿

このような回答には修正を依頼しましょう。

回答へのコメント

alphya

2018/12/30 10:30 編集

yohhoyさん、回答ありがとうございます! 規格(ドラフト)のパラグラフもありがとうございます!! 欲しかった情報です...! 私も[temp.inst]は探したのですが、そのNoteのgoogle翻訳がよく分からなく、見逃してました......orz (質問2は、インスタンス化さえしなかったら、phase2はしてもいいのではと思っていたのですが、"phase2=インスタンス化"と考えると確かに関係ありそうでした...!)←無視してくださいorz 調べていただいてありがとうございました!! またご縁がありましたらよろしくお願いいたします! ヾ(●>д<)ノThank You

1

ベストアンサー

こんにちは。

質問1: case: 2 の S{}() は、get()が定義される際になぜ評価されないのでしょうか。

case: 2のSは省略しないで記述すると、get<T>()::Sになりますので形式的にはTに依存していることになるようです。

質問2: constexpr ifとtwo-phase name lookupは関係があったのでしょうか。

テンプレート内で参照されるテンプレート引数に依存した名前の解決はtwo-phase name lookupされると理解しています。(two-phase name lookupについては良く知らないですが、アセンブラの1パス、2パスと同様な問題と理解しています。余談ですがC/C++も2パスを許せば本当に楽になるのですが...)

通常は1phase目に名前解決されます。しかし、テンプレート引数に与える「型」についてテンプレートを定義する前に全て定義されていることを必須とするのはナンセンスと思います。テンプレートを定義する前に明示的実体化的に引数を全て指定する必要がありますから。そこで、1phase目ではテンプレート引数に依存した名前は未解決であることを許しているのだと思います。

そして、2phase目はテンプレートの実体化時に行われる筈です。その際constexpr ifは条件が成立しない方の2phase目以降を実行しないということではないでしょうか?
コンパイル時に決定できるものですからそれでOKと思います。通常のif文は実行時に分岐する「建前」なので通常のif文にするとアサートします。

ああ、そうすると前回書いた「実体化を遅延する効果」とう表現は不適切でした。通常のif文でもテンプレート引数に依存したものは当然「実体化は遅延」されます。通常のif文では実体化が抑制されないので普通にアサートするわけです。
「実体化を抑制する効果」と書くべきでした。(リンク先もそう書いてありました。申し訳ないです。)

投稿2018/12/29 08:03

編集2018/12/29 08:04
Chironian

総合スコア23251

alphya👍を押しています

良いと思った回答にはグッドを送りましょう。
グッドが多くついた回答ほどページの上位に表示されるので、他の人が素晴らしい回答を見つけやすくなります。

下記のような回答は推奨されていません。

  • 間違っている回答
  • 質問の回答になっていない投稿
  • スパムや攻撃的な表現を用いた投稿

このような回答には修正を依頼しましょう。

回答へのコメント

alphya

2018/12/30 10:31 編集

Chironianさん、回答ありがとうございます!! 質問1について、本当にありがとうございました!! これで、[]{return false;}() が使えます! (質問2については、"実体化と名前解決は違うもの"と考えていたのですが、"実体化=名前解決"と考えると確かに関係があると思いました!)←無視してください(泣) この度も本当にお世話になりました!! ヾ(●>д<)ノThank You

1

cpp

1constexpr S() = default;

ちょっと余談ですが、trivialなcopy/move ctorは暗黙でconstexprになるからつけるなみたいな話を思い出しました。


普通にgetに依存する名前だと思ったんですが自信がなくなってきた・・・

投稿2018/12/29 05:58

yumetodo

総合スコア5850

alphya👍を押しています

良いと思った回答にはグッドを送りましょう。
グッドが多くついた回答ほどページの上位に表示されるので、他の人が素晴らしい回答を見つけやすくなります。

下記のような回答は推奨されていません。

  • 間違っている回答
  • 質問の回答になっていない投稿
  • スパムや攻撃的な表現を用いた投稿

このような回答には修正を依頼しましょう。

回答へのコメント

alphya

2018/12/29 07:30 編集

yumetodoさん、回答ありがとうございます。 >ちょっと余談ですが、trivialなcopy/move ctorは暗黙でconstexprになるからつけるなみたいな話を思い出しました。 暗黙でconstexprになるのですか!なるほど、リテラル型ではないものが渡されるとill-formedになるので、コンパイラにやってもらおうと...! 確かにconstexpr S() = default;は冗長でした、編集しておきます。 >普通にgetに依存する名前だと... ClangもgetのTに依存すように動くので、そう考えると自然ですよね... そうなると、[]{return false;}()がfalse_vの代わりになれるのですが、私も自信がなくて...
yumetodo

2018/12/29 09:03

lambdaってどうなんだろう、常にユニークな型になるんだから依存名である必要は無さそうに思える・・・(要調査
yumetodo

2018/12/29 09:10

あれっ、trivialなcopy/move ctorは暗黙でconstexprになる、は真だけど、=default指定はuser-providedにあたるから、その時点でtrivialなcopy/move ctorではないような・・・ ref: https://qiita.com/yumetodo/items/424cc4d15de4edad436a あー、自分でも混乱してきた。
alphya

2018/12/29 09:14

yumetodoさん、コメントありがとうございます! ラムダに関しては、http://eel.is/c++draft/expr.prim.lambda.closure に、 >ラムダ式の型(これはクロージャオブジェクトの型でもあります)は、クロージャ型と呼ばれる固有の名前のない共用体ではないクラス型です。そのプロパティについては後述します。 >クロージャ型は、対応するラムダ式を含む最小のブロックスコープ、クラススコープ、またはネームスペーススコープで宣言されます。 とあるので、この場合のラムダ式はget関数テンプレート内のブロックスコープに含まれており、クロージャ型はそこで宣言されていると思います!!
yumetodo

2018/12/29 09:15

おお、それはしらなかった。
yumetodo

2018/12/29 09:19 編集

ああ、自分の記事をよく読め案件だったでござる >= default/= delete 指定されたものはuser-provided やっぱり=default指定に加えたconstexprは冗長ですね。
alphya

2018/12/29 09:23

>ctor/assgin opに対する=default指定に加えたconstexprは冗長 調べてくださってありがとうございます! また機会があればよろしくお願いします!! ヾ(●>д<)ノThank You

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

ただいまの回答率
86.12%

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

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

質問する

関連した質問

同じタグがついた質問を見る

C++

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