🐥

clang で C++ テンプレートで -Wundefined-func-template のメモ

2024/02/05に公開

テンプレートの実装をヘッダに書きたくない...
(コードサイズが増えてめんどい)

また各翻訳単位でインスタンス化だとプログラムサイズが増えてつらいので, ライブラリ(プログラム)でインスタンス化は一個だけにしたい.

//myfunc.hh
#pragma once

template<class T>
void myfunc(T x, float y);
#include <iostream>

#include "tmpl.hh"

template<class T>
void myfunc(T x, float y) {
  std::cout << "bora" << x << ", " << y << "\n";
}

template void myfunc<double>(double x, float y);
// main.cc
#include <iostream>
#include "myfunc.hh"

int main(int argc, char **argv) {
  myfunc<double>(1.0, 2.0f);
}

のような.

しかし,

https://github.com/llvm/llvm-project/issues/52653

にあるように, ヘッダには template の定義だけだと, clang で warning level を上げている場合 -Wundefined-func-template のエラーが出る.

C++11 以降くらいなら, unknown な template のシンボル解決はリンク時に行う, で問題ない(warn にする必要ない)ようなな気もしますけどね.

解決

extern template でいけます.

[C++11] extern templateの機能とその使い道
https://qiita.com/Kogia_sima/items/b7a1e23a78f81d913089

ありがとうございます.

今回のケースでは myfunc.hh or main.cc

extern template void myfunc<double>(double x, float y);

を記述すれば OK.

extern template は, グローバル変数とかの extern と同じ感じで, どこかに template の実体があるよ, と教えてあげる感じですね.

問題点

ただ, この解決はテンプレートで展開する型がわかっているケースに限られます.

コードをライブラリとして提供し, ユーザーが任意の型を与えることを想定するケースでは,
上記 qiita 記事にありますように, ヘッダにテンプレートの実装を書き, ライブラリビルド時かライブラリ利用時かで ifdef で制御することになるでしょう...

Discussion