A
abir
Hi,
I have a situation, where i cant implement a template member
function in a header, as it uses a forward declared class. If i want
to do it in the cpp, where the forward declared class is fully
defines, i have to specialize it for all possible implementation,
which looks same.
Is there any trick, so that linker find the implementation (i am
sure there is some ) ?
The following code describes the problem,
I have stroke class & letter class , a vector of which are stored in
stroke_context
//stroke_context.hpp
#ifndef _stroke_context_hpp_
#define _stroke_context_hpp_
#include "stroke_fwd.hpp"
#Include "letter_fwd.hpp"
#include "letter.hpp"
#include "stroke.hpp"
namespace test{
struct stroke_context{
STROKEV strokes;
LETTERV letters;
};
}
#endif
//stroke_fwd.hpp forward decl for stroke (to use iterator)
#ifndef _stroke_fwd_hpp_
#define _stroke_fwd_hpp_
#include <vector>
namespace test{
struct stroke;
typedef std::vector<stroke> STROKEV;
}
#endif
///letter_fwd.hpp forward decl for letter (to use iterator)
#ifndef _letter_fwd_hpp_
#define _letter_fwd_hpp_
#include <vector>
namespace test{
struct letter;
typedef std::vector<letter> LETTERV;
}
#endif
now, stroke has the letter index & stroke context, and returns an
iterator for letter.
#ifndef _stroke_hpp_
#define _stroke_hpp_
#include "letter_fwd.hpp"
namespace test{
struct stroke_context;
struct stroke{
std::size_t letterId;
stroke_context* ctx;
stroke(std::size_t letterId) : letterId(letterId){}
LETTERV::iterator get_letter();
};
}
#endif
//stroke.cpp
#include "stroke.hpp"
#include "letter.hpp"
#include "stroke_context.hpp"
namespace test{
LETTERV::iterator stroke::get_letter(){
return ctx->letters.begin()+letterId;
}
}
so, fas it is fine with forward decl of iterator, and implementation
in cpp file where ctx is fully defined.
The problem comes for letter implementation, which has 2 strokes and
returns them.
//letter.hpp
#ifndef _letter_hpp_
#define _letter_hpp_
#include "index.hpp"
#include "stroke_fwd.hpp"
namespace test{
struct stroke_context;
struct letter{
stroke_context* ctx;
index2 strokeID;
template<dir_type>
STROKEV::iterator get_stroke();
};
}
#endif
where , index.hpp is,
#ifndef _index_hpp_
#define _index_hpp_
#include <cstddef>
namespace test{
enum dir_type{
dir_x,dir_y
};
struct index2{
std::size_t x;
std::size_t y;
template<dir_type>
std::size_t& get();
template<> std::size_t& get<dir_x>(){ return x;}
template<> std::size_t& get<dir_y>(){ return y;}
};
}
#endif
now, as i can't implement STROKEV::iterator get_stroke() in the header
(as it uses undefined class stroke_context) , i have to implement it
it cpp (just like i did it for stroke also).
however as this is template over direction, i cant implement it it cpp
without specialization (linker wont find it in that case). an for
specialization, all of them looks just same, causing code repetition.
at present, letter.cpp looks like,
#include "letter.hpp"
#include "stroke_context.hpp"
namespace test{
template<>
STROKEV::iterator letter::get_stroke<dir_x>(){
return ctx->strokes.begin()+strokeID.get<dir_x>();
}
template<>
STROKEV::iterator letter::get_stroke<dir_y>(){
return ctx->strokes.begin()+strokeID.get<dir_y>();
}
}
this works fine, but causes code repetition. I want to get rid of
that.
any suggestion is welcome.
Thanks
abir
I have a situation, where i cant implement a template member
function in a header, as it uses a forward declared class. If i want
to do it in the cpp, where the forward declared class is fully
defines, i have to specialize it for all possible implementation,
which looks same.
Is there any trick, so that linker find the implementation (i am
sure there is some ) ?
The following code describes the problem,
I have stroke class & letter class , a vector of which are stored in
stroke_context
//stroke_context.hpp
#ifndef _stroke_context_hpp_
#define _stroke_context_hpp_
#include "stroke_fwd.hpp"
#Include "letter_fwd.hpp"
#include "letter.hpp"
#include "stroke.hpp"
namespace test{
struct stroke_context{
STROKEV strokes;
LETTERV letters;
};
}
#endif
//stroke_fwd.hpp forward decl for stroke (to use iterator)
#ifndef _stroke_fwd_hpp_
#define _stroke_fwd_hpp_
#include <vector>
namespace test{
struct stroke;
typedef std::vector<stroke> STROKEV;
}
#endif
///letter_fwd.hpp forward decl for letter (to use iterator)
#ifndef _letter_fwd_hpp_
#define _letter_fwd_hpp_
#include <vector>
namespace test{
struct letter;
typedef std::vector<letter> LETTERV;
}
#endif
now, stroke has the letter index & stroke context, and returns an
iterator for letter.
#ifndef _stroke_hpp_
#define _stroke_hpp_
#include "letter_fwd.hpp"
namespace test{
struct stroke_context;
struct stroke{
std::size_t letterId;
stroke_context* ctx;
stroke(std::size_t letterId) : letterId(letterId){}
LETTERV::iterator get_letter();
};
}
#endif
//stroke.cpp
#include "stroke.hpp"
#include "letter.hpp"
#include "stroke_context.hpp"
namespace test{
LETTERV::iterator stroke::get_letter(){
return ctx->letters.begin()+letterId;
}
}
so, fas it is fine with forward decl of iterator, and implementation
in cpp file where ctx is fully defined.
The problem comes for letter implementation, which has 2 strokes and
returns them.
//letter.hpp
#ifndef _letter_hpp_
#define _letter_hpp_
#include "index.hpp"
#include "stroke_fwd.hpp"
namespace test{
struct stroke_context;
struct letter{
stroke_context* ctx;
index2 strokeID;
template<dir_type>
STROKEV::iterator get_stroke();
};
}
#endif
where , index.hpp is,
#ifndef _index_hpp_
#define _index_hpp_
#include <cstddef>
namespace test{
enum dir_type{
dir_x,dir_y
};
struct index2{
std::size_t x;
std::size_t y;
template<dir_type>
std::size_t& get();
template<> std::size_t& get<dir_x>(){ return x;}
template<> std::size_t& get<dir_y>(){ return y;}
};
}
#endif
now, as i can't implement STROKEV::iterator get_stroke() in the header
(as it uses undefined class stroke_context) , i have to implement it
it cpp (just like i did it for stroke also).
however as this is template over direction, i cant implement it it cpp
without specialization (linker wont find it in that case). an for
specialization, all of them looks just same, causing code repetition.
at present, letter.cpp looks like,
#include "letter.hpp"
#include "stroke_context.hpp"
namespace test{
template<>
STROKEV::iterator letter::get_stroke<dir_x>(){
return ctx->strokes.begin()+strokeID.get<dir_x>();
}
template<>
STROKEV::iterator letter::get_stroke<dir_y>(){
return ctx->strokes.begin()+strokeID.get<dir_y>();
}
}
this works fine, but causes code repetition. I want to get rid of
that.
any suggestion is welcome.
Thanks
abir