I
Ioannis Gyftos
Hello,
First the code
///////////////////////////////////////////////////////////////////////////////////
// in another header file
namespace LJC{
struct DomainInterface {
... // pure virtual functions
};
struct ConnectionTypeInterface {
... // pure virtual functions
};
struct Domain {
struct Local : public DomainInterface
{
...
};
struct Internet : public DomainInterface
{
...
};
};
struct ConnectionType {
struct Stream : public ConnectionTypeInterface
{
...
};
struct Datagram : public ConnectionTypeInterface
{
...
};
};
.....
}; // end of namespace
///////////////////////////////////////////////////////////////////////////////////
template <
class DomainInterface,
class ConnectionTypeInterfaceclass Connection{
public:
Connection(const int port);
Connection(const char* address);
int init();
private:
DomainInterface Domain;
ConnectionTypeInterface ConnectionType;
};
// This works.
template <>
inline Connection<
LJC:omain::Internet,
LJC::ConnectionType:atagram
}
// This works.
template <
class DomainInterface,
class ConnectionTypeInterfaceinline Connection<DomainInterface,
ConnectionTypeInterface>::Connection(const char* a)
{
}
// This does not work with the error message:
// invalid use of incomplete type ‘class
Connection<LJC:omain::Internet, ConnectionTypeInterface>’
// declaration of ‘class Connection<LJC:omain::Internet,
ConnectionTypeInterface>’
template <
class ConnectionTypeInterfaceinline Connection<
LJC:omain::Internet,
ConnectionTypeInterface
}
// This works
template <
class DomainInterface,
class ConnectionTypeInterfaceint Connection<DomainInterface, ConnectionTypeInterface>::init()
{
}
///////////////////////////////////////////////////////////////////////////////////
To give some background on what I am trying to do:
I have recently created some TCP, UDP and UnixSocket libraries with
very similar interface for different projects. After getting inspired
by Alexandrescu's book, I was trying to combine those in a single
templated 'Connection' class, which would use such templates to define
protocols and policies (like server/client, blocking/non-blocking
function calls). The general flow of either of these combination is
similar, so I figured I would train myself into creating something
like this.
The specific problem I was trying to solve is the constructor call. A
class instantiated with Domain::Local should be constructed with a
const char* (socket path), but a class instantiated with
Domain::Internet should use an integer (port). To solve this, I though
I would create two constructors, one with char* and one with int. I
would implement a partial template specialization for <Internet,int>
and one for <Local,char*>, so if a user would call it with correct
combination it would work, but if he tried to call a wrong one it
would throw a compiler undefined reference error.
I looked around the web, some books etc, but I could not understand
why am I getting this error. I can use the constructor unspecialized
or fully specialized, but not partially. Full specialization is not
really acceptable since I plan to add more template parameters later
(starting of slow). Most examples I found on the net use ints or bools
while partially specializing, I tried with those but I got the same
result (I am saying this because I stumbled across someone mentioning
that I couldn't use a class for specialization, but I am confused
about what he meant).
I also read something else on the net, which I did not fully
understand; the partial specialization failed because the top-level
class is templated for <class DomainInterface, class
ConnectionTypeInterface>, and there is no top-level class
specialization for the partial-specialized case. Following this, I
tried (with several combinations) something like this:
template <
class ConnectionTypeInterfaceclass Connection{
public:
Connection(const int port);
Connection(const char* address);
....
};
But I got redefinition error messages.
Can what I describe above be done? If so, what is my mistake and how
can it be corrected? My C++ intuition so far tells me that it does,
but if it's impossible, I haven't thought of a secondary plan so far,
so I might ask later on
First the code
///////////////////////////////////////////////////////////////////////////////////
// in another header file
namespace LJC{
struct DomainInterface {
... // pure virtual functions
};
struct ConnectionTypeInterface {
... // pure virtual functions
};
struct Domain {
struct Local : public DomainInterface
{
...
};
struct Internet : public DomainInterface
{
...
};
};
struct ConnectionType {
struct Stream : public ConnectionTypeInterface
{
...
};
struct Datagram : public ConnectionTypeInterface
{
...
};
};
.....
}; // end of namespace
///////////////////////////////////////////////////////////////////////////////////
template <
class DomainInterface,
class ConnectionTypeInterfaceclass Connection{
public:
Connection(const int port);
Connection(const char* address);
int init();
private:
DomainInterface Domain;
ConnectionTypeInterface ConnectionType;
};
// This works.
template <>
inline Connection<
LJC:omain::Internet,
LJC::ConnectionType:atagram
{::Connection(const char* a)
}
// This works.
template <
class DomainInterface,
class ConnectionTypeInterfaceinline Connection<DomainInterface,
ConnectionTypeInterface>::Connection(const char* a)
{
}
// This does not work with the error message:
// invalid use of incomplete type ‘class
Connection<LJC:omain::Internet, ConnectionTypeInterface>’
// declaration of ‘class Connection<LJC:omain::Internet,
ConnectionTypeInterface>’
template <
class ConnectionTypeInterfaceinline Connection<
LJC:omain::Internet,
ConnectionTypeInterface
{::Connection(const char* a)
}
// This works
template <
class DomainInterface,
class ConnectionTypeInterfaceint Connection<DomainInterface, ConnectionTypeInterface>::init()
{
}
///////////////////////////////////////////////////////////////////////////////////
To give some background on what I am trying to do:
I have recently created some TCP, UDP and UnixSocket libraries with
very similar interface for different projects. After getting inspired
by Alexandrescu's book, I was trying to combine those in a single
templated 'Connection' class, which would use such templates to define
protocols and policies (like server/client, blocking/non-blocking
function calls). The general flow of either of these combination is
similar, so I figured I would train myself into creating something
like this.
The specific problem I was trying to solve is the constructor call. A
class instantiated with Domain::Local should be constructed with a
const char* (socket path), but a class instantiated with
Domain::Internet should use an integer (port). To solve this, I though
I would create two constructors, one with char* and one with int. I
would implement a partial template specialization for <Internet,int>
and one for <Local,char*>, so if a user would call it with correct
combination it would work, but if he tried to call a wrong one it
would throw a compiler undefined reference error.
I looked around the web, some books etc, but I could not understand
why am I getting this error. I can use the constructor unspecialized
or fully specialized, but not partially. Full specialization is not
really acceptable since I plan to add more template parameters later
(starting of slow). Most examples I found on the net use ints or bools
while partially specializing, I tried with those but I got the same
result (I am saying this because I stumbled across someone mentioning
that I couldn't use a class for specialization, but I am confused
about what he meant).
I also read something else on the net, which I did not fully
understand; the partial specialization failed because the top-level
class is templated for <class DomainInterface, class
ConnectionTypeInterface>, and there is no top-level class
specialization for the partial-specialized case. Following this, I
tried (with several combinations) something like this:
template <
class ConnectionTypeInterfaceclass Connection{
public:
Connection(const int port);
Connection(const char* address);
....
};
But I got redefinition error messages.
Can what I describe above be done? If so, what is my mistake and how
can it be corrected? My C++ intuition so far tells me that it does,
but if it's impossible, I haven't thought of a secondary plan so far,
so I might ask later on