前回,ハマったのはこんなサンプルプログラムでした.
/**** lib/Calc.cc ****/
#ifndef __CALC_H
#define __CALC_H
#include <iostream>
using namespace std;
class Calc
{
public:
Calc();
~Calc();
int add(int a, int b);
};
#endif
/**** lib/Calc.cc ****/
#include <Calc.h>
Calc::Calc()
{
cout<<"Calc constructor"<<endl;
}
Calc::~Calc()
{
cout<<"Calc destructor"<<endl;
}
int Calc::add(int a, int b)
{
return(a+b);
}そしてテストプログラム.ちょっと綺麗に改編.
/**** test/test_Calc.cc ****/
#include <cppcutter.h>
#include <Calc.h>
namespace testCacl
{
void test_Calc()
{
Calc calc;
cppcut_assert_equal(3, calc.add(1,2));
}
}共有ライブラリを作成.前回,酔っ払ってarを使ってスタティックライブラリを作っていたので,コマンドを修正.
> g++ -o lib/libCalc.so lib/Calc.cc -Ilib -I/usr/local/include/cutter -shared -fPIC
テストコードの共有ライブラリ化.
> g++ -o test/test_Calc.so test/test_Calc.cc -Llib -lCalc -L/usr/local/lib -lcppcutter -lcutter -Ilib -I/usr/local/include/cutter -shared -fPIC
実行!
> env LD_LIBRARY_PATH=./lib cutter -v v test/ testCacl: testCacl::test_Calc: Calc constructor Calc destructor .: (0.000241) Finished in 0.001482 seconds (total: 0.000241 seconds) 1 test(s), 1 assertion(s), 0 failure(s), 0 error(s), 0 pending(s), 0 omission(s), 0 notification(s) 100% passed
今回ハマったのは,テンプレートの導入です.
テストプログラムを微妙に書き換えてみます.
/**** test/test_Calc.cc ****/
#include <cppcutter.h>
#include <Calc.h>
namespace testCacl
{
void test_Calc()
{
Calc calc;
cppcut_assert_equal(4.0, calc.add(1.5,2.5));
}
}実行!
> env LD_LIBRARY_PATH=./lib cutter -v v test/ testCacl: testCacl::test_Calc: Calc constructor F: (0.000582) 1) Failure: testCacl::test_Calc <4.0 == calc.add(1.5,2.5)> expected: <4> actual: <3> test/test_Calc.cc:9: void testCacl::test_Calc()(): cppcut_assert_equal(4.0, calc.add(1.5,2.5), ) Finished in 0.001993 seconds (total: 0.000582 seconds) 1 test(s), 0 assertion(s), 1 failure(s), 0 error(s), 0 pending(s), 0 omission(s), 0 notification(s) 0% passed
1.5+2.5=4を期待したけど,切捨てられて1+2=3になったのでテスト失敗です!当たり前!
そこで,intじゃなくてdoubleも気軽に対応したいと,ライブラリを書き換えます.
/**** lib/Calc.h ****/
#ifndef __CALC_H
#define __CALC_H
#include <iostream>
using namespace std;
template<class C> class Calc
{
public:
Calc();
~Calc();
C add(C a, C b);
};
#endif
/**** lib/Calc.cc ****/
#include <Calc.h>
template<class C> Calc<C>::Calc()
{
cout<<"Calc constructor"<<endl;
}
template<class C> Calc<C>::~Calc()
{
cout<<"Calc destructor"<<endl;
}
template<class C> C Calc<C>::add(C a, C b)
{
return(a+b);
}テストコードもちょっとだけ変更.
/**** test/test_Calc.cc ****/
#include <cutter.h>
#include <Calc.h>
namespace testCacl
{
void test_Calc()
{
Calc<double> calc;
cut_assert_equal_double(4.0, 0.1, calc.add(1.5,2.5));
}
}テスト実行!
> env LD_LIBRARY_PATH=./lib cutter -v v test/ testCacl: testCacl::test_Calc: /libexec/ld-elf.so.1: test/test_Calc.so: Undefined symbol "_ZN4CalcIdEC1Ev"
へ?
> nm lib/libCalc.so |grep _ZN4CalcIdEC1Ev >
確かにありません.
悩んだあげく,ライブラリのソースを微妙に書き換えました.
/**** lib/Calc.cc ****/
#include <Calc.h>
template<class C> Calc<C>::Calc()
{
cout<<"Calc constructor"<<endl;
}
template<class C> Calc<C>::~Calc()
{
cout<<"Calc destructor"<<endl;
}
template<class C> C Calc<C>::add(C a, C b)
{
return(a+b);
}
template class Calc<double>;すると,
> nm lib/libCalc.so |grep _ZN4CalcIdEC1Ev 00000cb0 W _ZN4CalcIdEC1Ev
あるじゃないですか,今度は.テスト実行!
> env LD_LIBRARY_PATH=./lib cutter -v v test/ testCacl: testCacl::test_Calc: Calc constructor Calc destructor .: (0.000225) Finished in 0.001446 seconds (total: 0.000225 seconds) 1 test(s), 1 assertion(s), 0 failure(s), 0 error(s), 0 pending(s), 0 omission(s), 0 notification(s) 100% passed >
Ok.
これは,Stroustrupのc++本
の最後の方に書かれてあった,「明示的なインスタンス生成」がうまくいったようです.
Cutter, 引き続き便利に使えてます!