template specialization problem

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
 
O

Ondra Holub

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

You would need compiler with working keyword export. But it is not
widely supported.

I usually implement such functions/methods in separate header file
(usually with different suffix) and then I create special cpp file,
which only includes all these "implementation headers".
 
M

Michael DOUBEZ

abir a écrit :
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,
[snip: lot of code]
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();
};
}
[snip]
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
[snip: code]
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.

You can expose a helper function (in a helper namespace if you want):
STROKEV::iterator begin(stroke_context* strokes);

That you implement in a cpp file with the full includes:
LETTERV::iterator begin(stroke* strokes)
{
return ctx->letters.begin();
}


And then, later on:
template<dir_type>
STROKEV::iterator get_stroke()
{
return begin(ctx)+strokeID.get<dir_type>();
}

Michael
 
A

abir

abir a écrit :


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,
[snip: lot of code]
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();
};
}
[snip]
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
[snip: code]
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.

You can expose a helper function (in a helper namespace if you want):
STROKEV::iterator begin(stroke_context* strokes);

That you implement in a cpp file with the full includes:
LETTERV::iterator begin(stroke* strokes)
{
return ctx->letters.begin();

}

And then, later on:
template<dir_type>
STROKEV::iterator get_stroke()
{
return begin(ctx)+strokeID.get<dir_type>();

}

Michael

Thanks for answering.
This is a wonderful method.
but in actual code, even letters is a templated over dir_type.
so, again the problem is with begin function implementation.
however, i think, using a special template source file to write the
function , and including it prior to calling is helpful.
thanks again to the community ...
abir
 

Ask a Question

Want to reply to this thread or ask your own question?

You'll need to choose a username for the site, which only take a couple of moments. After that, you can post your question and our members will help you out.

Ask a Question

Members online

No members online now.

Forum statistics

Threads
474,262
Messages
2,571,056
Members
48,769
Latest member
Clifft

Latest Threads

Top