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.
I don't think this questions relates to quantitative finance at all, but I'll answer anyway.
You have not provided an implementation to the constructor of the class OISCurve.
To link your program, do this:
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>())
: <Call Parent Constructor>
{
}
You will need to replace with a call to an actual constructor defined in PiecewiseYieldCurve. There are six such constructors, so you will need to select the one that you think most appropriate. Please note that you will need to give the parent constructor a list of instruments, but it's missing in your constructor definition.
Related
I have a Feature class which has a public vehicle_type in it and I have 3 candidates for vehicle_type variable which are; Car,Truck and Motor classes. When I call constructor for Feature class, well I want my program to get which vehicle type was called with constructor automatically. I actually tried to use Templates for the problem but it didn't work. So, can someone tell me how to achieve this with or without using Templates.
This is my Feature.h file:
#ifndef FEATURE_H
#define FEATURE_H
#include <string>
#include "../includes/Car.h"
#include "../includes/Truck.h"
#include "../includes/Motor.h"
template <typename T>
class Feature{
public:
Feature();
Feature(int w, std::string b, std::string clr, double p, T v_t);
T vehicle_type;
int wheels;
std::string brand;
std::string color;
double price;
};
#endif
This is my Feature.cpp file:
# include "../includes/Feature.h"
template <typename T>
Feature::Feature(int w, std::string br, std::string clr, double p, T v_t){wheels = w; brand=br; color = clr; price=p; vehicle_type = v_t; }
Feature::Feature(){}
and lastly, this below is the error occurs when I hover my mouse on Feature constructor in the Feature.cpp file.
name followed by '::' must be a class or namespace name
Feel free to ask for more information. Thanks.
It looks like you just need to supply the template declaration and the fix the syntax:
template <typename T>
Feature<T>::Feature(int w, std::string br, std::string clr, double p, T v_t);
template<class T>
Feature<T>::Feature();
I've a function std::vector<Token> tokenize(const std::string& s) that I want to unit test. The Token struct is defined as follows:
enum class Token_type { plus, minus, mult, div, number };
struct Token {
Token_type type;
double value;
}
I have set up CppUnitTest and can get toy tests such as 1 + 1 == 2 to run. But when I try to run a test on my tokenize function it gives me this error:
Error C2338: Test writer must define specialization of ToString<const Q& q> for your class class std::basic_string<wchar_t,struct std::char_traits<wchar_t>,class std::allocator<wchar_t> > __cdecl Microsoft::VisualStudio::CppUnitTestFramework::ToString<class std::vector<struct Token,class std::allocator<struct Token> >>(const class std::vector<struct Token,class std::allocator<struct Token> > &).
My testing code is this:
#include <vector>
#include "pch.h"
#include "CppUnitTest.h"
#include "../calc-cli/token.hpp"
using namespace std;
using namespace Microsoft::VisualStudio::CppUnitTestFramework;
namespace test_tokens {
TEST_CLASS(test_tokenize) {
public:
TEST_METHOD(binary_operation_plus) {
auto r = tokenize("1+2");
vector<Token> s = {
Token{ Token_type::number, 1.0 },
Token{ Token_type::plus },
Token{ Token_type::number, 2.0}
};
Assert::AreEqual(r, s);
}
};
}
What's causing the error and how can I fix this?
When you use Assert::AreEqual the framework wants to be able to display a string that describes the objects if the assert fails. It uses the templated function ToString for this, which includes specializations for all the basic data types. For any other data type, you would have to provide a specialization that knows how to format the data into a meaningful string.
The simplest solution is to use a different type of assert that doesn't require ToString. For example:
Assert::IsTrue(r == s, L"Some descriptive failure message");
The other option is to create the ToString specialization that the assert needs:
#include <CppUnitTestAssert.h>
namespace Microsoft {
namespace VisualStudio {
namespace CppUnitTestFramework {
template<> static inline std::wstring ToString(const std::vector<Token> &t)
{
// Write some code here to create a descriptive std::wstring
return std::wstring("My object description");
}
}
}
}
I would only go to the trouble of making a specialization if I'm going to be writing a lot of tests using that same object type, and I want to automatically describe the objects.
I'm trying to build a simple heap data structure for practice. When I build the version for double it works fine.
class heapt {
public:
heapt();
heapt(std::initializer_list<double> lst);
void print_heapt();
private:
int size;
int length;
double* elem; //points to root
};
Its constructors works perfectly and the heap is printed as it should. But when I try to generalize it with
template< typename Elem>
as:
template<typename Elem>
class heapt {
public:
heapt();
heapt(std::initializer_list<Elem> lst);
void print_heapt();
private:
int size;
int length;
Elem* elem; //points to root
};
for the class definition and as:
template<typename Elem>
heapt<Elem>::heapt(std::initializer_list<Elem> lst) :
size{ static_cast<int>(lst.size()) },
elem{new Elem[lst.size()]}
{
std::copy(lst.begin(), lst.end(), elem);//Now heaptify elem
build_heapt(elem, lst.size());
}
for one of the constructors used in the main function.
I get two linking errors:
LNK2019 unresolved external symbol "public: void __thiscall heapt::print_heapt(void)" (?print_heapt#?$heapt#H##QAEXXZ) referenced in function _main
LNK2019 unresolved external symbol "public: __thiscall heapt::heapt(class std::initializer_list)" (??0?$heapt#H##QAE#V?$initializer_list#H#std###Z) referenced in function _main
The main function is:
{
heapt<int> hh{ 27,12,3,13,2,4,14,5 };
std::cout << "Hello" << '\n';
hh.print_heapt();
}
EDIT: The heapt class is in the "heap.h" file and the definition for the constructor heapt<Elem>::heapt(std::initializer_list<Elem> lst) is in the "heap.cpp" class, which has #include"heap.h" as a header file. The int main function is in a file named "InSo.cpp", which also has #include"heap.h" as a header file.
In your templated class declaration you are using heapt(std::initializer_list<double> lst); but in your definition you are using std::initializer_list<Elem>. You should change the declaration to heapt(std::initializer_list<Elem> lst);
You are still missing definitions for print_heapt and build_heapt but otherwise it should compile.
EDIT: In light of you clarifying how your source files are set up, see WhozCraig's comment on your initial post. You can either include the definition of the templated class functions in a heap.hpp file, for example, and include it at the end of your heap.h, or just put them all together in one file, e.g.
// heap.h
#ifndef HEAP_H
#define HEAP_H
#include <initializer_list>
template<typename Elem>
class heapt {
public:
heapt();
heapt(std::initializer_list<Elem> lst);
void print_heapt();
private:
int size;
int length;
Elem* elem; //points to root
};
#include "heap.hpp"
#endif
//heap.hpp
#ifndef HEAP_HPP
#define HEAP_HPP
#include "heap.h"
#include <algorithm>
template<typename Elem>
heapt<Elem>::heapt(std::initializer_list<Elem> lst) :
size{ static_cast<int>(lst.size()) },
elem{ new Elem[lst.size()] }
{
std::copy(lst.begin(), lst.end(), elem);//Now heaptify elem
//build_heapt(elem, lst.size());
}
#endif
I wrote a code with template copy constructor to get a better understanding of the concept as I am new to it but the following code fails to compile
#include <iostream>
#include <vector>
using namespace std;
template <typename T>
class Grid
{
public:
explicit Grid(size_t inWidth = kDefaultWidth, size_t inHeight = kDefaultHeight);
virtual ~Grid();
template <typename E>
Grid(const Grid<T>& src);
static const size_t kDefaultWidth = 10;
static const size_t kDefaultHeight = 10;
std::vector<std::vector<T>> mCells;
size_t mWidth, mHeight;
};
template <typename T>
template <typename E>
Grid<T>::Grid(const Grid<T>& src)
{
cout << "Copy constructor working " << endl;
}
int main()
{
Grid<double> myDoubleGrid;
Grid<double> newDoubleGrid(myDoubleGrid);
return 0;
}
On compiling the above code in visual studio following error appears:-
ERROR:-
Severity Code Description Project File Line Suppression State
Error C2558 class 'Grid': no copy constructor available or copy constructor is declared 'explicit'
I have tried to replace the argument's template with E and It shows more errors (strange ones)
template <typename T>
template <typename E>
Grid<T>::Grid(const Grid<E>& src)
{
cout << "Copy constructor working " << endl;
}
Errors:
Severity Code Description Project File Line Suppression State
Error LNK2019 unresolved external symbol "public: __thiscall Grid::Grid(unsigned int,unsigned int)" (??0?$Grid#N##QAE#II#Z) referenced in function _main
Error LNK1120 2 unresolved externals
Error LNK2019 unresolved external symbol "public: virtual __thiscall Grid::~Grid(void)" (??1?$Grid#N##UAE#XZ) referenced in function "public: virtual void * __thiscall Grid::`scalar deleting destructor'(unsigned int)" (??_G?$Grid#N##UAEPAXI#Z)
A template constructor is never(!) a copy constructor. The constructor in your code is a converting constructor, only.
You may want both:
#include <iostream>
#include <vector>
// Please do not have this ugliness in a header!
using namespace std;
template <typename T>
class Grid
{
public:
explicit Grid(size_t inWidth = kDefaultWidth, size_t inHeight = kDefaultHeight)
// initialize members ...
{}
// Without this copy-constructor the compiler generates a copy-constructor
// (with no output, of course)
Grid(const Grid& src)
// initialize members ...
{
cout << "Copy constructor" << endl;
}
template <typename E>
Grid(const Grid<E>& src)
// initialize members ...
{
cout << "Converting constructor" << endl;
}
static const size_t kDefaultWidth = 10;
static const size_t kDefaultHeight = 10;
size_t mWidth, mHeight;
};
int main()
{
Grid<double> myDoubleGrid;
Grid<double> newDoubleGrid(myDoubleGrid); // Copy constructor
Grid<int> newIntGrid(myDoubleGrid); // Converting constructor
return 0;
}
See also:
http://en.cppreference.com/w/cpp/language/copy_constructor
http://en.cppreference.com/w/cpp/language/converting_constructor
Derive from template constuctor of template base class
Note that Grid<T>(Grid<U> const&) is not technically a copy constructor, it is a converting constructor. The compiler still generates a copy constructor for you.
The thing to which you call as dangerous error is happening because of your silly mistakes:-
1) You have provided declarations for both constructors and destructors. And as you are saying that it is your one and only source file. It means that you must have not defined them and which is the reason for the linker errors that you are getting. Sometimes these pretty simple problems can prove to be very dangerous and time consuming.
You could have replaced the semicolon with a pair of braces if you don't want to provide any detailed implementation.
2) The thing that you are trying to do is completely logicless as you are creating a converter constuctor with the ssignature similar to copy constructor. Anyway compiler will give preference to copy constructor than your converter constructor.
Ultimately your definition for the constructor will never actually be called.
Sorry for my bad English. I have 2 projects. Project 1 is a MFC dll that contains class CMyContainer, class CEmployee. Project 2 is my main project. In project 2, I created an instance of CMyContainer of type CEmployee. Now I want to sort the container but I got an error
"error LNK2019: unresolved external symbol "bool __cdecl MyComparer(class CEmployee *,class CEmployee *)" (?MyComparer##YA_NPAVCEmployee##0#Z) referenced in function "public: void __thiscall CMyContainer<class CEmployee>::sortContainer(void)" (?sortContainer#?$CMyContainer#VCEmployee####QAEXXZ)"
How can I fix this problem?
// file MyContainer.h in project 1
#include <vector>
template <class T>
class _declspec(dllexport) CMyContainer
{
public:
CMyContainer(void);
~CMyContainer(void);
...
void sortContainer();
private:
std::vector<T*> items;
typename std::vector<T*>::iterator it;
};
template <class T> void CMyContainer<T>::sortContainer()
{
typedef bool (*comparer_t)(T*,T*);
comparer_t cmp = &MyComparer;
std::sort(items.begin(), items.end(), cmp);
}
//File Employee.h in project 1
#include "MyContainer.h"
class _declspec(dllexport) CEmployee
{
public:
CEmployee(void);
~CEmployee(void);
void setEmployeeCode(CString);
CString getEmployeeCode();
friend bool MyComparer(CEmployee*, CEmployee*);
private:
CString m_szEmployeeCode;
}
//File Employee.cpp in project 1
void CEmployee::setEmployeeCode(CString val){
m_szEmployeeCode= val;
}
CString CEmployee::getEmployeeCode(){
return m_szEmployeeCode;
}
bool MyComparer(CEmployee*pEmp1, CEmployee*pEmp2)
{
return (pEmp1->getEmployeeCode().Compare(pEmp2->getEmployeeCode())<0);
}
//File main.cpp in project 2
#include <..\Models\MyContainer.h>
#include <..\Models\Employee.h>
...
CMyContainer<CEmployee> *pListEmployee;
... // insert into pListEmployee
// sort pListEmployee
pListEmployee.sortContainer();//-> This command cause error
Try to export MyComparer from the .dll with _declspec(dllexport)