Sign in to follow this  

Temlpate instantiation problem (part 2)

This topic is 3732 days old which is more than the 365 day threshold we allow for new replies. Please post a new topic.

If you intended to correct an error in the post then please contact us.

Recommended Posts

<edit> My first problem is solved. For my second problem, see below. </edit> The problem is explained in the code:
class One {};
class Two : virtual public One {};

template <class T> class Three : public Two
{
	public :
		Three () {};
		template <class U> Three (const Three <U> & other) {};
};

class A {};
template <class T> class B : public A {};

class X {};

template class B <X>;

template class Three <A>;
template class Three <B <X> >;

//	This line gives a 'template-id ... does not match any template declaration' error.
//	(This would work if 'Two' wouldn't inherit 'One' virtual.)
//	template Three <A> :: Three (const Three <B <X> > & other);

//	Someone on the GameDev.net IRC channel suggested this solution,
//	but it only seems to work for non-template classes (like A).
//	Here I get a '... is not a valid type for a template constant parameter' error.
template <class A>
	template <class B <X> > /* Here's the problem. */
	Three <A> :: Three (const Three <B <X> > & other);

int main ()
{
	Three <B <X> > B3;
	Three <A> A3 (B3);

	return 0;
}




[Edited by - Taldor on October 28, 2007 2:41:31 PM]

Share this post


Link to post
Share on other sites
template <class A>
template <class B>
Three <A> :: Three (const Three <B> & other);
?

Share this post


Link to post
Share on other sites
Quote:
Original post by ToohrVyk
template <class A>
template <class B>
Three <A> :: Three (const Three <B> & other);
?

Okay, that works. :-) I thought that the argument type had to be a fully defined class, but apparently that's incorrect. Thanks!

Now a similar problem with templates & namespaces...

abc.hpp:

class One {};
class Two : virtual public One {};

template <class T> class Three :
public Two
{
public :
Three () {};
template <class U> Three (const Three <U> & other);
};






abc.cpp:

#include "abc.hpp"

namespace XX
{
class X {};
}
namespace YY
{
class Y {};
}

namespace AA
{
template <class T> class A {};
}
namespace BB
{
template <class T> class B : public AA :: A <XX :: X> {};
}

template class AA :: A <XX :: X>;
template class BB :: B <YY :: Y>;

template class Three <AA :: A <XX :: X> >;
template class Three <BB :: B <YY :: Y> >;


// This gives errors:
// 'invalid use of template-name ... without an argument list'
template <class AA :: A>
template <class BB :: B>
Three <AA :: A> :: Three (const Three <BB :: B> & other);

int main ()
{
Three <BB :: B <XX :: X> > B3;
Three <AA :: A <YY :: Y> > A3 (B3);

return 0;
}






What should I do here?

[Edited by - Taldor on October 28, 2007 2:19:04 PM]

Share this post


Link to post
Share on other sites
template <class SomeCompletelyIrrelevantName>
template <class AnotherCompletelyIrrelevantName>
Three <SomeCompletelyIrrelevantName> :: Three (
const Three <AnotherCompletelyIrrelevantName> & other);

Share this post


Link to post
Share on other sites
Quote:
Original post by ToohrVyk
template <class SomeCompletelyIrrelevantName>
template <class AnotherCompletelyIrrelevantName>
Three <SomeCompletelyIrrelevantName> :: Three (
const Three <AnotherCompletelyIrrelevantName> & other);

No, the names are relevant, otherwise I end up with linking errors. Here's explained why I do this.

Share this post


Link to post
Share on other sites
Quote:
Original post by Taldor
No, the names are relevant, otherwise I end up with linking errors. Here's explained why I do this.


They are irrelevant, in that the compiler will simply ignore them—they're template parameters, not template arguments, and as such their name has no impact on the code beyond the obvious search-and-replace effect that occurs when an argument is provided for a parameter.

Of course, if you're trying to manually instantiate your templates by hand, then the entire template<class FooBar> contraption is useless (as it forward-declares a template without instantiating it) independently of your template arguments being templates or your namespace issues.

In the end, I'm afraid I have no clue about why introducing virtual inheritance eliminates that template constructor. The closest I could get was:
template<class C1,class C2>
void convert(const C2 & o)
{
return (void) C1(o);
}

template convert< Three<A>, Three< B<X> > >
convert(const Three< B<X> > &)


Which should force the instantiation of the adapted constructor.

Share this post


Link to post
Share on other sites
Quote:
Original post by ToohrVyk
template<class C1,class C2>
void convert(const C2 & o)
{
return (void) C1(o);
}

template convert< Three<A>, Three< B<X> > >
convert(const Three< B<X> > &)



Sadly, this only works in this example and not in my actual code. ('One' corresponds to 'boost :: noncopyable', 'Two' to 'Reference_Base' and 'Three' to 'Reference'. I'd like to make 'Reference_Base' inheriting virtual from 'boost :: noncopyable', but I didn't upload it as such yet, because of this problem.)

Share this post


Link to post
Share on other sites
Quote:
Original post by Taldor
Sadly, this only works in this example and not in my actual code.


Erm. You're much more familiar with your own code than I am, so could you please say what the exact problem is in adapting this example to your code? The way I see it, you merely have to define a function which calls the appropriate constructor (something which should be possible if you ever intended to call that constructor in the first place);

Share this post


Link to post
Share on other sites
Any constructor declared in the child will prevent the compiler from even attempting to match against this template in the parent. I have no idea if this is relevant, but someone mentioned constructors.

Share this post


Link to post
Share on other sites
Okay, forget that, I've looked at it.

//	This gives errors:
// 'invalid use of template-name ... without an argument list'
template <class AA::A>
template <class BB::B>
Three<AA::A>::Three(const Three<BB::B> & other);


First, typenames are generally much easier to read without spaces in them.
Second, If you're trying to specialize this constructor, it would look more like


template <> Three<AA::A>::Three(const Three<BB::B>&);

Share this post


Link to post
Share on other sites
Quote:
Original post by Deyja
Second, If you're trying to specialize this constructor, it would look more like


It seems that he's not trying to specialize it, just to instantiate it.

Share this post


Link to post
Share on other sites
Quote:
Original post by ToohrVyk
Quote:
Original post by Taldor
Sadly, this only works in this example and not in my actual code.


Erm. You're much more familiar with your own code than I am, so could you please say what the exact problem is in adapting this example to your code? The way I see it, you merely have to define a function which calls the appropriate constructor (something which should be possible if you ever intended to call that constructor in the first place);

I was wrong, I don't think it works in the example either, as I'm (trying to) instantiate the copy constructor you use in the convert function, so wrapping it in a function won't help, I believe.

Share this post


Link to post
Share on other sites
Quote:
Original post by Taldor
I was wrong, I don't think it works in the example either, as I'm (trying to) instantiate the copy constructor you use in the convert function, so wrapping it in a function won't help, I believe.


Using [foo] in a function will always instantiate [foo] if the function itself is instantiated at a point where the definition of [foo] is visible (that's the way template instantiation works). And so, by instantiating convert, I indirectly instantiate the constructor used inside.

Share this post


Link to post
Share on other sites
Quote:
Original post by ToohrVyk
Using [foo] in a function will always instantiate [foo] if the function itself is instantiated at a point where the definition of [foo] is visible (that's the way template instantiation works). And so, by instantiating convert, I indirectly instantiate the constructor used inside.



template <class FROM, class TO> void convert (const FROM & from)
{
return (void) TO (from);
}

template void convert <Three <BB :: B <YY :: Y> >, Three <AA :: A <XX :: X> > > (const Three <BB :: B <YY :: Y> > & from);



Using this code, I get this error: "undefined reference to `Three<AA::A<XX::X> >::Three<BB::B<YY::Y> >(Three<BB::B<YY::Y> > const&)'". So apparently it isn't instantiated.

Share this post


Link to post
Share on other sites
test.cpp
#include <iostream>

// Definition without function bodies

class One {};
class Two : public One {};

template <class T> class Three : public Two
{
public :
Three ();
template <class U> Three (const Three <U> &);
};

namespace AA
{
class A {};
}

namespace BB
{
template <class T> class B : public AA::A {};
}

class X {};

// Calls

int main()
{
Three< BB::B<X> > bx;
Three< AA::A > a (bx);
}



defs.cpp
#include <iostream>

// Definitions

class One {};
class Two : public One {};

template <class T> class Three : public Two
{
public :
Three () {}
template <class U> Three (const Three <U> &) { std::cout << "Bar\n"; }
};

namespace AA
{
class A {};
}

namespace BB
{
template <class T> class B : public AA::A {};
}

class X {};

// Instanciation

template Three< BB::B<X> >::Three();


template<class C1, class C2>
void convert(const C2& o)
{
return (void) C1(o);
}

template void convert< Three<AA::A>, Three< BB::B<X> > >(const Three< BB::B<X> > &);



Compiles fine for me and outputs "Bar" even though neither constructor is available in the file where they are called. Using g++ 3.4.0

Share this post


Link to post
Share on other sites
Sign in to follow this