VS Code(または Code::Blocks)+MinGW の構成で C++ の <thread> を使おうとすると、std::thread や std::this_thread::sleep_for が「定義されていない」と出てコンパイルできないことがあります。原因は多くの場合、C++11 以降が有効になっていないか、MinGW 自体が古いこと。この記事では、最短で切り分けて確実に直すための手順を具体例つきで整理します。
起きている症状を整理する
今回のトラブルは、だいたい次のような状態として現れます。
std::threadが未宣言・未定義扱いになるstd::this_threadが未宣言・未定義扱いになる(例:this_thread was never definedなど)- オンラインコンパイラ(online-cpp.com 等)では同じコードが動く
- pthread を入れたつもりでも改善しない
重要なのは、「コンパイル段階のエラー」なのか「リンク段階のエラー」なのかです。std::thread が定義されていない 系はたいてい コンパイル段階の問題で、まず疑うべきは C++ の規格設定と MinGW の世代です。
先に結論:原因はほぼこの二択
この問題の原因は、現場ではほぼ次の二択に収束します。
| 原因 | 起きやすい症状 | 最優先の対処 |
|---|---|---|
| C++11以降が有効になっていない | <thread> を include しても std::thread / std::this_thread が見つからない | -std=c++20(最低でも -std=c++11)を確実に付ける |
| MinGW(GCC/標準ライブラリ)が古い | 規格オプションを付けても改善しない/環境によってはヘッダが不完全 | MinGW-w64 系など、スレッド対応が整った配布物へ更新する |
「pthread を入れたのに…」という相談は多いのですが、今回の主症状が “未定義(コンパイルエラー)” の場合、pthread を足す前に 規格オプションと MinGW 更新が本命です。
pthread 系のオプションは、状況によっては必要ですが、優先順位は後になります(後述します)。
なぜオンラインコンパイラだと動くのか
オンラインコンパイラは、最初から C++17 や C++20 がデフォルトになっていたり、比較的新しい GCC と標準ライブラリを使っていることが多いです。
一方、ローカル環境の MinGW は、
- デフォルトが古い規格(例:C++98 相当)になっている
- そもそも GCC/標準ライブラリが古くて
<thread>周りが弱い - PATH の先頭に「昔入れた別の g++」が残っていて、意図しないコンパイラが動いている
といった理由で差が出ます。特に最後の「別の g++ が動いている」は、本人が気づきにくい地雷です。
まずは現状確認:今動いている g++ を特定する
設定を直す前に、最初にやるべきことは「いま VS Code やターミナルが使っている g++ が何者か」を確定させることです。
コマンドで確認する
VS Code のターミナル(PowerShell / CMD)で次を実行します。
g++ --version
where g++
g++ --version で GCC の世代感が分かり、where g++ で “どのパスの g++ が呼ばれているか” が一覧で出ます。
ここで複数行出る場合は要注意で、VS Code のビルドが「自分の想定とは別の g++」を使っていることがよくあります。
規格が効いているかを確認する
次のコードで、コンパイル時の __cplusplus(規格の目安)を表示できます。
#include <iostream>
int main() {
std::cout << __cplusplus << "\n";
}
出力値の目安は次の通りです。
| __cplusplus の値 | だいたいの規格 | 意味 |
|---|---|---|
| 199711L | C++98/03 | この状態だと <thread> は基本的に使えない。まず規格オプションが必要 |
| 201103L | C++11 | <thread> を使う最低ライン。古い MinGW だと実装が弱い場合も |
| 201402L | C++14 | 実用上はこの辺以上が安心 |
| 201703L | C++17 | 近年の標準的な環境 |
| 202002L | C++20 | 今回はこの設定を推奨(環境差でハマりにくい) |
もし 199711L が出ているなら、ほぼ確実に「規格が古い」が原因です。次の章の設定を優先してください。
対処の第一優先:C++20 を有効化してビルドする
<thread> は C++11 からの機能です。つまり、最小でも -std=c++11 が必要です。
ただし Windows の MinGW 環境は配布物や設定が混在しがちなので、記事としては 最初から -std=c++20 を明示するのが安全です(問題の切り分けも簡単になります)。
コマンドラインでの基本形
まずは VS Code を介さず、手打ちで通る形を作ると早いです。
g++ main.cpp -std=c++20 -O2 -Wall -Wextra -pedantic -o app.exe
ここで通れば、あとは VS Code の tasks.json に同じオプションを入れるだけです。
VS Code の tasks.json に -std=c++20 を入れる
VS Code の「タスクでビルド」や拡張機能からビルドしている場合、実体は tasks.json の引数です。典型例を載せます(必要最低限の形)。
{
"version": "2.0.0",
"tasks": [
{
"label": "build (g++)",
"type": "shell",
"command": "g++",
"args": [
"-std=c++20",
"-O2",
"-Wall",
"-Wextra",
"-pedantic",
"${file}",
"-o",
"${fileDirname}\\${fileBasenameNoExtension}.exe"
],
"group": {
"kind": "build",
"isDefault": true
},
"problemMatcher": [
"$gcc"
]
}
]
}
ポイントは、必ず args に -std=c++20 を入れることです。
「設定したつもり」でも、別タスクを実行していたり、Code Runner の設定が別にあったりすると、オプションが付かないままビルドされてハマります。
gnu++20 と c++20 はどちらが良いか
-std=c++20 は純粋な標準準拠寄り、-std=gnu++20 は GCC 拡張も許可するモードです。
Windows の現場だと、外部ライブラリや環境依存コードの都合で gnu++20 が必要になるケースもありますが、<thread> の問題自体はどちらでも解決します。迷うならまず -std=c++20 でOKです。
規格を上げてもダメなとき:MinGW が古い可能性が高い
-std=c++20 を付けても std::thread が “存在しない扱い” のままなら、MinGW(GCC/標準ライブラリ)が古い可能性が高いです。
特に、昔からある「MinGW(mingw.org 系)」を使っていると、C++11 以降の機能が弱い、または更新が止まっていてハマりやすいです。
MinGW と MinGW-w64 の違いをざっくり掴む
| 系統 | 特徴 | スレッド周りの期待値 | おすすめ度 |
|---|---|---|---|
| 古い MinGW(いわゆる mingw.org 系) | 昔からある。環境によって情報が混在しやすい | <thread> 周りでハマりやすい | 避けたい |
| MinGW-w64 系 | 64bit/32bit を含み、更新が活発な配布物が多い | 比較的安定。winpthread を含む構成も多い | 推奨 |
「MinGW を入れた」と言っていても、実際には複数の配布物が混ざっていることがあります。まずは where g++ の出力で、どのディレクトリの g++ を使っているかを確認してください。
MinGW を更新する現実的な選択肢
更新方法はいくつかありますが、共通して重要なのは「更新後に VS Code が新しい g++ を確実に使う状態にする」ことです。更新しても PATH が古いままだと、症状が変わりません。
選択肢の例
- MinGW-w64 を含む配布物へ切り替える(例:MSYS2 系、WinLibs 系など)
- 古い MinGW を PATH から外す(優先順位の問題を潰す)
- VS Code のタスクが参照する g++ を固定する(フルパス指定)
特に手堅いのは、タスクの command を g++ ではなく、フルパスにする方法です。これなら PATH の混乱に強くなります。
"command": "C:\\msys64\\mingw64\\bin\\g++.exe"
このように指定しておけば、他に古い g++ が残っていても、ビルドだけは確実に狙ったコンパイラで実行できます。
更新後に必ずやるチェック
更新した直後は、次のチェックを必ず行ってください。
| チェック項目 | 確認方法 | 狙い |
|---|---|---|
| VS Code のターミナルで新しい g++ が見えている | where g++ / g++ --version | PATH の優先順位ミスを潰す |
| ビルドタスクが同じ g++ を使っている | tasks.json をフルパス指定、または task 実行ログを確認 | ターミナルとビルドで別物を使っている事故を潰す |
-std=c++20 が実際に付いている | ビルド出力にコマンドラインを出す設定にする | 「設定したつもり」を潰す |
リンクエラーに変わった場合の話:-pthread と winpthread
今回の相談は「定義されていない」という コンパイルエラーが中心ですが、規格や MinGW を整えると、症状が一段階進んで「未定義参照」つまり リンクエラーに変わることがあります。
代表例としては次のようなパターンです。
undefined reference to ...が出るstd::threadは見えるようになったが、リンクで落ちる
この場合、環境によっては -pthread を付けることで解決します。まずは次の形を試します。
g++ main.cpp -std=c++20 -O2 -Wall -Wextra -pthread -o app.exe
ポイント
-pthreadは「スレッド利用を前提にビルド・リンクする」ためのオプションで、環境によって必要になります- Windows の MinGW-w64 では内部的に winpthread を使う構成があり、ここで差が出ることがあります
- ただし、今回の主症状が “宣言が見えない” 場合は、まず
-stdと MinGW 更新が先です
もし -pthread を足しても解決しない場合は、そもそも別の標準ライブラリや別の g++ を使っている(混在している)可能性が高いので、再度 where g++ に戻って確認してください。
エラー文から逆引きする早見表
ハマりやすいエラーと対処の対応表です。まずはここで自分の症状の位置づけを掴むと早いです。
| エラー例 | 段階 | よくある原因 | 優先対処 |
|---|---|---|---|
‘thread’ is not a member of ‘std’ | コンパイル | C++11以降になっていない/ヘッダを include していない | #include <thread> と -std=c++20 |
‘this_thread’ has not been declared | コンパイル | 規格が古い/MinGW が古い/std::this_thread の名前空間ミス | -std=c++20、改善しなければ MinGW 更新 |
this_thread was never defined | コンパイル | 規格が古い・標準ライブラリが古い・環境混在 | __cplusplus を確認し、-std と MinGW-w64 化 |
undefined reference to ... std::thread ... | リンク | スレッドライブラリのリンク不足(環境差) | -pthread を追加 |
| VS Code は補完できるのにビルドだけ失敗 | 設定 | IntelliSense と tasks のコンパイラが別 | tasks の g++ を固定し、IntelliSense 側も合わせる |
動作確認に使える最小サンプル
切り分けでは「自分のプロジェクト」ではなく、まず最小コードで通るかを見るのが最短です。次のコードは std::thread と std::this_thread::sleep_for の両方を使います。
#include <iostream>
#include <thread>
#include <chrono>
int main() {
std::cout << "start\n";
std::thread t([]{
std::cout << "worker: sleep...\n";
std::this_thread::sleep_for(std::chrono::milliseconds(300));
std::cout << "worker: wake\n";
});
t.join();
std::cout << "done\n";
}
コンパイル例はこれです。
g++ main.cpp -std=c++20 -O2 -Wall -Wextra -pedantic -pthread -o app.exe
この最小サンプルが通れば、環境として <thread> は使える状態です。あとは自分のプロジェクト側の設定(ビルド手順や CMake、タスク)に原因が残っています。
VS Code でありがちな落とし穴
VS Code は「補完」と「ビルド」が別設定になりやすいのが難点です。よくある落とし穴をまとめます。
補完が通るのにビルドが落ちる
これは、IntelliSense(C/C++ 拡張)が参照しているコンパイラと、tasks.json の g++ が別物になっているケースが多いです。
- IntelliSense は新しい MinGW-w64 を参照
- ビルドは PATH 上の古い MinGW を参照
というズレが起きると、「エディタでは問題なさそうなのにビルドだけ失敗」という状態になります。
対策としては次のどれかが効きます。
- tasks.json の
commandを g++ のフルパスにする - Windows の環境変数 PATH を整理して、古い MinGW を外す
- VS Code の設定や拡張機能で、使用コンパイラを統一する
Code Runner を使っていてオプションが付いていない
Code Runner はワンクリックで実行できて便利ですが、デフォルト設定だと -std=c++20 が付かず、古い規格でコンパイルされることがあります。
この場合は「タスクでビルド+実行」に寄せるか、Code Runner 側の設定で -std=c++20 を付与してください。
複数ファイルのときに ${file} だけをビルドしている
スレッドの問題とは別件ですが、プロジェクトが複数ファイルになっているのに tasks.json が ${file} だけをコンパイルしていて、別ファイルがリンクされていないことがあります。
この場合、エラーが <thread> とは違う形で出て混乱しやすいので、プロジェクトが大きい場合は CMake などのビルドシステムを使うのも有効です。
Code::Blocks での確認ポイント
Code::Blocks の場合も、根本は「規格」と「コンパイラの世代」です。確認ポイントは次の通りです。
- 使用しているコンパイラがどこを指しているか(設定画面の Toolchain executables)
- コンパイラオプションに
-std=c++20(最低でも-std=c++11)を入れているか - 古い MinGW が同梱されている Code::Blocks をそのまま使っていないか
Code::Blocks は同梱 MinGW が古い構成もあり、その場合は更新した MinGW-w64 を明示的に紐づける必要があります。
現場でのおすすめ手順
最短で解決するための順番を、実務向けにまとめます。
| 順番 | やること | 判断基準 |
|---|---|---|
| 最初 | where g++ と g++ --version で実体を特定 | 複数出たら混在の可能性大 |
| 次 | 最小サンプルを -std=c++20 付きでビルド | 通れば環境はOK、プロジェクト設定へ |
| 通らない | MinGW を MinGW-w64 系へ更新 | 更新後も where g++ を再確認 |
| リンクで落ちる | -pthread を追加 | 未定義参照ならこの段階 |
まとめ
<thread>が「定義されていない」系のエラーは、まず C++11以降の有効化を疑う- VS Code では tasks.json に
-std=c++20を入れるのが定番で、最も再現性が高い - それでも直らないなら、MinGW が古い可能性が高いので MinGW-w64 系へ更新する
- 症状がリンクエラーに変わったら
-pthreadを試す - 更新しても直らないときは、ほぼ確実に 別の g++ を使っているので
where g++に戻る

コメント