C++編で扱っている C++ は 2003年に登場した C++03
という、とても古いバージョンのものです。C++ はその後、C++11 -> C++14
-> C++17 -> C++20 -> C++23 と更新されています。
なかでも C++11 での更新は非常に大きなものであり、これから C++
の学習を始めるのなら、C++11
よりも古いバージョンを対象にするべきではありません。特に事情がないなら、新しい
C++ を学んでください。 当サイトでは、C++14 をベースにした新C++編を作成中です。
問題① クラステンプレートのメンバ関数の定義が、ヘッダ側に書かれていないと、その関数を使用できないことを確認してください。その後、明示的なインスタンス化を行うことで、この問題を解決できることを確認してください。
// Stack.h
#ifndef STACK_H_INCLUDED
#define STACK_H_INCLUDED
#include <cstddef>
template <typename T>
class Stack {
public:
typedef T value_type;
explicit Stack(std::size_t capacity);
~Stack();
void Push(const T& data);
void Pop();
inline const value_type Top() const
{
return mData[mSP - 1];
}
inline std::size_t GetSize() const
{
return mSP;
}
inline std::size_t GetCapacity() const
{
return mCapacity;
}
private:
const std::size_t mCapacity;
* mData;
Tint mSP;
};
#endif
// Stack.cpp
#include "Stack.h"
#include <cassert>
template <typename T>
<T>::Stack(std::size_t capacity) :
Stack(capacity),
mCapacity(new T[capacity]),
mData(0)
mSP{
}
template <typename T>
<T>::~Stack()
Stack{
delete [] mData;
}
template <typename T>
void Stack<T>::Push(const T& data)
{
assert(static_cast<std::size_t>(mSP) < mCapacity);
[mSP] = data;
mData++;
mSP}
template <typename T>
void Stack<T>::Pop()
{
assert(mSP > 0);
--;
mSP}
// main.cpp
#include <iostream>
#include "stack.h"
int main()
{
<int> iStack(10);
Stack
.Push(5);
iStackstd::cout << iStack.Top() << std::endl;
}
このプログラムを Visual Studio でビルドすると、次のようなエラーが出ます。
1>main.obj : error LNK2019: 未解決の外部シンボル "public: __thiscall Stack<int>::Stack<int>(unsigned int)" (??0?$Stack@H@@QAE@I@Z) が関数 _main で参照されました。
1>main.obj : error LNK2019: 未解決の外部シンボル "public: __thiscall Stack<int>::~Stack<int>(void)" (??1?$Stack@H@@QAE@XZ) が関数 _main で参照されました。
1>main.obj : error LNK2019: 未解決の外部シンボル "public: void __thiscall Stack<int>::Push(int const &)" (?Push@?$Stack@H@@QAEXABH@Z) が関数 _main で参照されました。
1>C:\test\Debug\CppTest2013.exe : fatal error LNK1120: 3 件の未解決の外部参照
これらはすべてリンク時のエラーで、それぞれ、コンストラクタ、デストラクタ、Pushメンバ関数の定義が見つからないことを報告しています。main関数内では、Topメンバ関数も使用していますが、これはインライン関数で、ヘッダ側に定義があるため、ちゃんと定義を見つけられていて、エラーになっていません。
今度は、stack.cpp の末尾に明示的なインスタンス化の指令を付け加えてみます。
// Stack.cpp
#include "Stack.h"
#include <cassert>
template <typename T>
<T>::Stack(std::size_t capacity) :
Stack(capacity),
mCapacity(new T[capacity]),
mData(0)
mSP{
}
template <typename T>
<T>::~Stack()
Stack{
delete [] mData;
}
template <typename T>
void Stack<T>::Push(const T& data)
{
assert(static_cast<std::size_t>(mSP) < mCapacity);
[mSP] = data;
mData++;
mSP}
template <typename T>
void Stack<T>::Pop()
{
assert(mSP > 0);
--;
mSP}
// 明示的なインスタンス化
template class Stack<int>;
今度は問題なくコンパイル・リンクが通り、実行できます。テンプレート仮引数に int型を当てはめる形で、明示的なインスタンス化を行っています。この場合、stack.cpp をコンパイルした時点で、Stack<int> のインスタンスが生成されており、main.cpp からも、このインスタンスが使われます。
VisualStudio 2015 の対応終了。
「VisualC++」という表現を「VisualStudio」に統一。
VisualC++ 2015 に対応。
新規作成。
Programming Place Plus のトップページへ
はてなブックマーク に保存 | Pocket に保存 | Facebook でシェア |
X で ポスト/フォロー | LINE で送る | noteで書く |
RSS | 管理者情報 | プライバシーポリシー |