I would like to derive a class template from QuantLib::PiecewiseYieldCurve. This is my derived class definition:
#include <ql\termstructures\yield\piecewiseyieldcurve.hpp>
#include <MarKetQuote\include\OISQuote.h>
#include <vector>
using namespace QuantLib;
/*! \brief Class to bootstrap an OIS curve.
*/
template <class Traits, class Interpolator,
template <class> class Bootstrap = IterativeBootstrap>
class OISCurve : public PiecewiseYieldCurve < Traits, Interpolator, Bootstrap >
{
private:
/** Typedef to refer to the specialized class.
It was necessary to add it in other to be able to declare the constructor as in QuantLib::PiecewiseYieldCurve.
*/
typedef OISCurve<Traits, Interpolator, Bootstrap> this_ois_curve;
public:
/** Constructor.
*/
OISCurve(
const Date& referenceDate,
const std::vector<OISQuote>& quotes,
const DayCounter& dayCounter,
Real accuracy,
const Interpolator& i = Interpolator(),
const Bootstrap<this_ois_curve>& bootstrap = Bootstrap<this_ois_curve>());
};
OISQuote is simply a class derived from QuantLib::SimpleQuote. I'm not familiar with this type of complicated templating, but to my limited understanding the above should be ok. It compiles actually. The problem arises when I try to instantiate a specialized class like this:
OISCurve<Discount, LogLinear> oisCurve = OISCurve<Discount, LogLinear>(Date::todaysDate(), quotes, Actual360(), 1.0e-12);
I get a linking error LNK2019 (using visual studio):
main.obj : error LNK2019: unresolved external symbol "public: __cdecl OISCurve<struct QuantLib::Discount,class QuantLib::LogLinear,class QuantLib::IterativeBootstrap>::OISCurve<struct QuantLib::Discount,class QuantLib::LogLinear,class QuantLib::IterativeBootstrap>(class QuantLib::Date const &,class std::vector<class OISQuote,class std::allocator<class OISQuote> > const &,class QuantLib::DayCounter const &,double,class QuantLib::LogLinear const &)" (??0?$OISCurve@UDiscount@QuantLib@@VLogLinear@2@VIterativeBootstrap@2@@@QEAA@AEBVDate@QuantLib@@AEBV?$vector@VOISQuote@@V?$allocator@VOISQuote@@@std@@@std@@AEBVDayCounter@2@NAEBVLogLinear@2@@Z) referenced in function main
1>C:\Users\u8998\PricingEngine\build\Debug\main.exe : fatal error LNK1120: 1 unresolved externals
Thanks for the help.
EDIT:
Sorry for the late reply. Thank you @LuigiBallabio and @StudentT for your answers. My problem ended up being caused by my inexperience with class templates. I had my declaration in a header file and my implementation in a cpp file exactly as with any other class. Following the guidelines in the accepted answer of this question I modified my code accordingly:
OISCurve.h
#ifndef OIS_CURVE_H
#define OIS_CURVE_H
#include <ql\termstructures\yield\piecewiseyieldcurve.hpp>
#include <ql\termstructures\yield\ratehelpers.hpp>
#include <ql\quote.hpp>
#include <vector>
#include <boost\shared_ptr.hpp>
using namespace QuantLib;
template <class Traits, class Interpolator,
template <class> class Bootstrap = IterativeBootstrap>
class OISCurve : public PiecewiseYieldCurve < Traits, Interpolator, Bootstrap >
{
public:
OISCurve(const Date& referenceDate,
const std::vector<boost::shared_ptr<Quote>>& quotes,
const DayCounter& dayCounter,
Real accuracy);
friend std::vector<boost::shared_ptr<RateHelper>> getRateHelpers(const std::vector<boost::shared_ptr<Quote>>& quotes);
private:
std::vector<boost::shared_ptr<Quote>> quotes_;
};
#include <CurveBootstrapping\src\OISCurve.cpp>
#endif
OISCurve.cpp
#include "OISCurve.h"
#include <ql\errors.hpp>
#include <algorithm>
#include <boost\foreach.hpp>
#include <ql\termstructures\yield\oisratehelper.hpp>
#include <MarKetQuote\include\OISQuote.h>
#include <ql\handle.hpp>
#include <ql\indexes\ibor\eonia.hpp>
#ifndef OIS_CURVE_IMPL
#define OIS_CURVE_IMPL
template <class T, class I, template <class> class B>
OISCurve<T, I, B>::OISCurve(
const Date& referenceDate,
const std::vector<boost::shared_ptr<Quote>>& quotes,
const DayCounter& dayCounter,
Real accuracy)
: PiecewiseYieldCurve < T, I, B >(referenceDate,
initializeQuotesAndGetRateHelpers(quotes),
dayCounter,
accuracy)
{
std::cout << "constructor works" << std::endl;
}
std::vector<boost::shared_ptr<RateHelper>> getRateHelpers(const std::vector<boost::shared_ptr<Quote>>& quotes)
{
QL_REQUIRE(std::all_of(quotes.begin(), quotes.end(), [](boost::shared_ptr<Quote> quote){ return boost::dynamic_pointer_cast<OISQuote>(quote) != 0; }),
"All quotes must be OISQuotes!");
std::vector<boost::shared_ptr<RateHelper>> rateHelpers;
BOOST_FOREACH(boost::shared_ptr<Quote> quote, quotes)
{
rateHelpers.push_back(boost::shared_ptr<RateHelper>(new OISRateHelper(2,
boost::dynamic_pointer_cast<OISQuote>(quote)->tenor(),
Handle<Quote>(quote),
boost::shared_ptr<OvernightIndex>(new Eonia()))));
}
return rateHelpers;
}
#endif
This is the solution i liked the most.