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

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

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

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

Q&A

解決済

2回答

682閲覧

fold式を使ったスカラー型のカウント方法のナゾ

jbe00214

総合スコア63

C++

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

0グッド

0クリップ

投稿2021/05/08 05:32

編集2021/05/08 05:37

前提・実現したいこと

畳み込み式を使って以前にスカラーの数をカウントする方法を教えていただいたのですが,次のコードになると,test_arg1とtest_arg2とでは動作が異なるのです。対処方法がわかりません。できればどこに問題があるのかも教えていただければ,幸いです。ご教示いただけるかたお願いします。

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

Static_assert failed due to requirement 'size == 3'

該当のソースコード

C++

1struct test_arg2{ 2 template < typename... Args> 3 auto operator()( Args&&... args ){ 4 constexpr int size = ( std::is_scalar_v<Args> + ... +0); 5 static_assert(size==3);//sizeは0 6 } 7}; 8 9template<typename... Args> 10struct test_arg1{ 11 test_arg1(Args&&... args){ 12 constexpr int size = ( std::is_scalar_v<Args> + ... +0); 13 static_assert(size==3);//ここはOK 14 test_arg2 f; 15 f(args...); 16 } 17}; 18 19int main (){ 20 test_arg1 f(1,1,1,vector{a3} ); 21} 22

試したこと

次のように直接呼び出すとうまくいきます。

C++

1int main(){ 2 test_arg2 g; 3 g(1,1,1,vector{a3} ); 4}

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

clang
c++17

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

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

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

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

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

guest

回答2

0

ベストアンサー

test_arg1とtest_arg2とでは動作が異なるのです。
直接呼び出すとうまくいきます。

test_arg2::operator()動作の差異は実引数の値カテゴリ(Value Category)の違い、つまり左辺値(lvalue)/右辺値(rvalue)の違いに起因します。

対処方法がわかりません。

値カテゴリを正しく伝搬させるには、std::forwardによる完全転送(Perfect Forwarding)を利用します。

c++

1template<typename... Args> 2struct test_arg1{ 3 test_arg1(Args&&... args){ 4 test_arg2 f; 5 f(std::forward<Args>(args)...); // ★修正後 6 } 7};

できればどこに問題があるのか

g経由のtest_arg2::operator()呼び出しでは右辺値1を渡しているため、テンプレートパラメータパックArgs{int, int, int, ...}に推論されます。つまりstd::is_scalar_v<Args> + ...は期待通りstd::is_scalar_v<int> + ...と評価されます。

c++

1test_arg2 g; 2g(1,1,1,vector{a3});

一方でg経由のtest_arg2::operator()呼び出し★では左辺値(のパック)args...を渡しているため、test_arg2側のArgs{int&, int&, int&, ...}と推論されます。言い換えると、test_arg1コンストラクタを経由するケースでは元の値カテゴリ情報が消失して、全て左辺値へ変換されています。

c++

1template<typename... Args> 2struct test_arg1{ 3 test_arg1(Args&&... args){ 4 test_arg2 f; 5 f(args...); // ★ 6 } 7};

投稿2021/05/08 09:49

編集2021/05/09 15:22
yohhoy

総合スコア6191

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

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

jbe00214

2021/05/08 11:55

ありがとうございます。解説でよくわかりました。気づきがないので,まだまだ勉強が足りていないようです。
guest

0

この場合には Args の型が int& と解されるからです。 int はもちろんスカラ型ですが int& はスカラ型ではありません。

is_scalar_v に渡す前に remove_reference_t を用いて参照をはがしてください。

投稿2021/05/08 07:45

SaitoAtsushi

総合スコア5466

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

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

jbe00214

2021/05/08 11:57

いつもありがとうございます。半日考えてもわかりませんでした。
guest

あなたの回答

tips

太字

斜体

打ち消し線

見出し

引用テキストの挿入

コードの挿入

リンクの挿入

リストの挿入

番号リストの挿入

表の挿入

水平線の挿入

プレビュー

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

ただいまの回答率
85.46%

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

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

質問する

関連した質問