概要
C++の線形代数ライブラリであるEigenのドキュメントのExampleをいろいろと試していたところ、以下のコードが出てきた。
#include <iostream>
#include <Eigen/Dense>
int main()
{
Eigen::MatrixXf A = Eigen::MatrixXf::Random(3, 2);
std::cout << "Here is the matrix A:\n" << A << std::endl;
Eigen::VectorXf b = Eigen::VectorXf::Random(3);
std::cout << "Here is the right hand side b:\n" << b << std::endl;
std::cout << "The least-squares solution is:\n"
<< A.template bdcSvd<Eigen::ComputeThinU | Eigen::ComputeThinV>().solve(b) << std::endl;
}
最後の文
A.template bdcSvd<Eigen::ComputeThinU | Eigen::ComputeThinV>().solve(b)
が全く理解できずにいたが、さらにコンパイルエラーにもなったので記載ミスかとも思ったが調べてみることにした。.template はdot templateと言うみたいです。
追記)
コメント欄に@SaitoAtsushiさんの解説がありますので、コメント欄も御覧ください。
実行環境
> g++ --version
Apple clang version 16.0.0 (clang-1600.0.26.6)
Target: arm64-apple-darwin24.3.0
Thread model: posix
InstalledDir: /Library/Developer/CommandLineTools/usr/bin
dot templateの調査
参照記事
実験
参照記事の2番目のサンプルコードに出力のコード追加して試してみます。
#include <iostream>
#include <vector>
struct X {
template <int N>
int get() const
{
return N;
}
};
int main()
{
typename std::vector<int>::iterator it; // OK
int value = X().template get<3>(); // OK
std::cout << "value = " << value << std::endl;
}
記事はC++11のところに記載されていたので、C++11以上なら大丈夫なようです。
> g++ test1.cc -std=c++11
> ./a.out
value = 3
上記のコードを今までのように書くとしたら、以下のようになるでしょう。
#include <iostream>
#include <vector>
struct X {
template <int N>
int get() const
{
return N;
}
};
int main()
{
std::vector<int>::iterator it;
int value = X().get<3>();
std::cout << "value = " << value << std::endl;
}
> g++ test2.cc -std=c++03
> ./a.out
value = 3
C++03でもコンパイルエラーはなかった。
今度はtemplateを使った関数printの中で試す。
#include <iostream>
#include <vector>
struct X {
template <int N>
int get() const
{
return N;
}
};
template<typename T> void print(T& x) {
int value = x.get<3>();
std::cout << "value = " << value << std::endl;
}
int main()
{
typename std::vector<int>::iterator it;
X xx = X();
print<X>(xx);
}
> g++ test3.cc -std=c++11
test3.cc:14:17: error: missing 'template' keyword prior to dependent template name 'get'
14 | int value = x.get<3>();
| ^ ~~~
1 error generated.
エラーになりました。
では、dot templateに戻してみます。
#include <iostream>
#include <vector>
struct X {
template <int N>
int get() const
{
return N;
}
};
template<typename T> void print(T& x) {
int value = x.template get<3>();
std::cout << "value = " << value << std::endl;
}
int main()
{
typename std::vector<int>::iterator it;
X xx = X();
print<X>(xx);
}
> g++ test4.cc -std=c++11
> ./a.out
value = 3
dot templateなら無事にコンパイルできました。
もう一つだけ試してみます。
#include <iostream>
#include <vector>
struct X {
template <int N>
int get() const
{
return N;
}
};
template<typename T>T print(X& x) {
int value = x.get<3>();
std::cout << "value = " << value << std::endl;
return (T)value;
}
int main()
{
typename std::vector<int>::iterator it;
X xx = X();
print<int>(xx);
}
Tのtemplateはなくても良かったのですが、一応残しました。
> g++ test5.cc -std=c++11
> ./a.out
value = 3
今までの使い方も確認できて良かったです。
templateで指定された型のオブジェクトのメンバーにtemplateが使われているときは
dot templatを使わないといけないのではないか、というのが自分なりの理解です。たぶん、これは1番目の参照記事が言っている事だとは思います。
終わりに
最初検索などをしてもtemplateで検索するとたくさん出てくるので、自分が知りたいものがdot templateだと分かるまでに時間がかかりました。さらに、dot templateの記事も少ないという状況でした。