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

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

新規登録して質問してみよう
ただいま回答率
85.50%
CentOS

CentOSは、主にRed Hat Enterprise Linux(RHEL)をベースにした、フリーのソフトウェアオペレーティングシステムです。

C++

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

Q&A

解決済

2回答

10596閲覧

threadクラスに渡す引数について

tpro

総合スコア27

CentOS

CentOSは、主にRed Hat Enterprise Linux(RHEL)をベースにした、フリーのソフトウェアオペレーティングシステムです。

C++

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

0グッド

2クリップ

投稿2017/03/05 16:56

ご覧くださりありがとうございます。

threadクラス及び関数オブジェクトの学習をしております。
下記コードをコンパイルしたら一部エラーが出ました。

C++

1#include <thread> 2#include <string> 3 4using namespace std; 5 6void foo() { 7 printf("mainとは別スレッドで実行されています\n"); 8} 9 10struct bar1 { 11 void operator() (const string& msg) const { 12 printf("%sが渡されました\n",msg.c_str()); 13 } 14}; 15 16struct bar2 { 17 void operator() () { 18 printf("引数なしです\n"); 19 } 20}; 21 22int main() { 23 thread th1(foo); 24 thread th2(bar1(), "An argument"); 25 thread th3(bar2()); 26 th1.join(); 27 th2.join(); 28 th3.join(); 29 30 return 0; 31}

エラーは以下のようにth3についてです。
__
main.cpp:25:13: warning: parentheses were disambiguated as a function
declaration [-Wvexing-parse]
thread th3(bar2());
^~~~~~~~
main.cpp:25:14: note: add a pair of parentheses to declare a variable
thread th3(bar2());
^
( )
main.cpp:28:6: error: member reference base type
'std::__1::thread (bar2 (*)())' is not a structure or union
th3.join();
__

bar2のインスタンスを作ってそれをthread引数に渡せば回避できることは把握しております。
ただ、
thread th2(bar1(), "An argument");
が通るのに
thread th3(bar2());
が通らないのがなんだか釈然としません。(上記エラーの意味もわかりません)

何が起きていてのエラーなのか、もしわかればC++11の理解が進み大変助かります。
ご存知の方がいらっしゃれば是非ご教示お願いいたします

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

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

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

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

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

guest

回答2

0

ベストアンサー

何が起きていてのエラーなのか、もしわかればC++11の理解が進み大変助かります。

これはC++11以前からC++言語に存在する「Most Vexing Parse」と呼ばれる問題です。直訳すれば「最も苛立たしい構文解析」でしょか。

thread th3(bar2());

上記のソースコードは、(大抵はプログラマの意図に反して)下記2通りのいずれかに解釈可能です。C++言語の仕様としては、下記のように「2通りに解釈可能なときは、変数宣言よりも後者の関数プロトタイプ宣言を優先する」と規定しています。

  1. thread型の変数th3の宣言。同変数をbar2型の一時オブジェクトbar2()を指定して初期化する。
  2. 戻り値がthread型かつ引数に“戻り値型bar2かつ引数を取らない関数へのポインタ型”をとる関数th3のプロトタイプ宣言。

註:厳密には「式または宣言のいずれにも解釈可能なときは、宣言を優先する」というルールです。本例ではbar2()部分がオブジェクト構築の式もしくは関数型宣言と解釈可能なため、構文解釈が曖昧となります。分かり易さのため、上記説明で理解してもさほど間違いないと思います。


下記いずれかの解決方法があります。いずれの方法も「関数プロトタイプ宣言としては解釈できない」ようにし、曖昧さをなくしています。

C++

1// 冗長な括弧()を使う。C++11以前でも利用できます。 2thread th3((bar2())); 3 4// 統一初期化構文{}を使う。C++11以降で利用できます。 5thread th3{bar2()}; // 外側 6thread th3(bar2{}); // 内側 7thread th3{bar2{}}; // 両方

投稿2017/03/06 00:54

編集2017/03/06 01:15
yohhoy

総合スコア6189

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

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

tpro

2017/03/06 04:25

2週刊くらいのもやもやが解けました。 統一初期化構文を知れたのも嬉しいです。 ご教示ありがとうございます!
yohhoy

2017/03/06 10:29

ご存知かもしれませんが https://cpprefjp.github.io/lang.html cpprefjpサイトでもC++11以降の新しい言語機能について概説しています。一度目を通されると俯瞰出来て良いかもしれませんね。
guest

0

こんにちは。

initializer listの解説に記載されている下記が原因と思います。

C++0xでは、()の代わりに、{}も使えるようになった。どちらも、同じ意味である。ただし、()を使った場合、以下のようなことはできない。

// これは、関数のプロトタイプ宣言。

// 引数を取らず、Foo型の戻り値を返す、wrongという名前の関数の宣言。
// Foo wrong(void)
Foo wrong() ;

'std::__1::thread (bar2 (*)())' is not a structure or union のメッセージをみると、thread th3(bar2());を、bar2を返却する関数ポインタを引数とし、threadを返却する関数the3()の宣言と解釈しているのだと思います。

thread th3{bar2()};

と修正すればコンパイル通りました。

th2については"An argument"のお陰でそのような誤解の余地がないと言うことだと思います。
コンパイラの開発者はこの問題を把握していて、できるだけプログラマの意図を汲み取ろうとしているのではないでしょうか?

投稿2017/03/05 17:23

編集2017/03/05 17:26
Chironian

総合スコア23272

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

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

tpro

2017/03/06 04:27

引用くださったサイト拝見しました。 今回の問題がよくわかりました。 ありがとうございます!
guest

あなたの回答

tips

太字

斜体

打ち消し線

見出し

引用テキストの挿入

コードの挿入

リンクの挿入

リストの挿入

番号リストの挿入

表の挿入

水平線の挿入

プレビュー

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

ただいまの回答率
85.50%

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

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

質問する

関連した質問