C++Talk.NET Forum Index C++Talk.NET
C++ language newsgroups
 
Archives   FAQFAQ   SearchSearch   MemberlistMemberlist   UsergroupsUsergroups   RegisterRegister 
 ProfileProfile   Log in to check your private messagesLog in to check your private messages   Log inLog in 

Template instantiation problem, take 2
Goto page 1, 2  Next
 
Post new topic   Reply to topic    C++Talk.NET Forum Index -> C++ Language (Moderated)
View previous topic :: View next topic  
Author Message
Kaba
Guest





PostPosted: Mon Sep 18, 2006 3:50 am    Post subject: Template instantiation problem, take 2 Reply with quote



Hello, I posted this problem to comp.lang.c++, but since I didn't get a
satisfying answer, I decided to post here.

Here is a short snippet of code that does not compile (tested with Vc8
and Comeau). This is because somehow Vector<0> gets instantiated, for
which the array size goes to 0. However, I don't quite get it why it
gets instantiated in the first place. So why does not this compile?

template <int N>
struct Vector
{
int data_[N];
};

template <int HEIGHT, int WIDTH>
struct Matrix
{
};

template <int HEIGHT, int WIDTH>
Vector<WIDTH> operator *(
const Vector<HEIGHT>&,
const Matrix<HEIGHT, WIDTH>&)
{
return Vector<WIDTH>();
}

template <int HEIGHT, int WIDTH>
Vector<WIDTH - 1> operator *(
const Vector<HEIGHT - 1>&,
const Matrix<HEIGHT, WIDTH>&)
{
return Vector<WIDTH - 1>();
}

int main()
{
Matrix<1, 1> transform;
Vector<1> translation;

translation = translation * transform;

return 0;
}

--
Kalle Rutanen
http://kaba.hilvi.org

[ See http://www.gotw.ca/resources/clcm.htm for info about ]
[ comp.lang.c++.moderated. First time posters: Do this! ]
Back to top
Kaba
Guest





PostPosted: Tue Sep 19, 2006 12:13 am    Post subject: Re: Template instantiation problem, take 2 Reply with quote



Quote:
This invokes (and thus instantiates) operator*( Vector<1
const&, Matrix<1, 1> const& ). The return type of this function
is Vector<0>. So instantiating this function triggers the
instantiation of Vector<0> (and the instantiation of Vector<0>'s
copy constructor, but that's no problem here).

Note there are two different versions of operator*.

Yes, that should invoke operator*( Vector<1> const&, Matrix<1, 1>
const&), as you say. But the return type is Vector<1>, not Vector<0>.
The second function can not possible match. Here is its code:

Quote:
template <int HEIGHT, int WIDTH
Vector<WIDTH - 1> operator *(
const Vector<HEIGHT - 1>&,
const Matrix<HEIGHT, WIDTH>&)
{
return Vector<WIDTH - 1>();
}

If it is concluded that the Matrix is Matrix<1,1> then it must be
concluded that HEIGHT = WIDTH = 1 and the other parameter would be
Vector<0>, but that is not the case, since it is Vector<1>. So no match.

If it is concluded that Vector is Vector<1>, then it must be concluded
that the Matrix is Matrix<2, something>, which is not the case, since it
is Matrix<1,1>. No match.

Quote:
I'm having a hard time seeing what you don't understand.

It might be because of the redundant example. Here's a more reduced
version:

template <int N>
struct Vector
{
int data_[N];
};

template <int N>
struct Matrix
{
};

template <int N>
int operator *(
const Vector<N>&,
const Matrix<N>&)
{
return 0;
}

template <int N>
int operator *(
const Vector<N - 1>&,
const Matrix<N>&)
{
return 1;
}

int main()
{
Matrix<1> transform;
Vector<1> translation;

int result = translation * transform;

return 0;
}

--
Kalle Rutanen
http://kaba.hilvi.org

[ See http://www.gotw.ca/resources/clcm.htm for info about ]
[ comp.lang.c++.moderated. First time posters: Do this! ]
Back to top
Thomas Tutone
Guest





PostPosted: Tue Sep 19, 2006 12:17 am    Post subject: Re: Template instantiation problem, take 2 Reply with quote



kanze wrote:
Quote:
Kaba wrote:

[snip]

Quote:
Here is a short snippet of code that does not compile (tested with Vc8
and Comeau). This is because somehow Vector<0> gets instantiated,

What do you mean, somehow? It rather obviously gets
instantiated.

for which the array size goes to 0. However, I don't quite get
it why it gets instantiated in the first place.

Because you use it.

So why does not this compile?

template <int N
struct Vector
{
int data_[N];
};

template <int HEIGHT, int WIDTH
struct Matrix
{
};

template <int HEIGHT, int WIDTH
Vector<WIDTH> operator *(
const Vector<HEIGHT>&,
const Matrix<HEIGHT, WIDTH>&)
{
return Vector<WIDTH>();
}

template <int HEIGHT, int WIDTH
Vector<WIDTH - 1> operator *(
const Vector<HEIGHT - 1>&,
const Matrix<HEIGHT, WIDTH>&)
{
return Vector<WIDTH - 1>();
}

int main()
{
Matrix<1, 1> transform;
Vector<1> translation;

translation = translation * transform;

This invokes (and thus instantiates) operator*( Vector<1
const&, Matrix<1, 1> const& ). The return type of this function
is Vector<0>. So instantiating this function triggers the
instantiation of Vector<0> (and the instantiation of Vector<0>'s
copy constructor, but that's no problem here).

return 0;
}

I'm having a hard time seeing what you don't understand. The
compiler does a transitive closure on the templates it
instantiates---instantiating one template will trigger the
instantiation of the template specializations which it uses.
This would seem an obvious implication; implicit instantiation
wouldn't be useful otherwise.

What's obvious to you, James, isn't all that obvious to me - I share
the OP's confusion. Why is the specialization of template<int, int>
operator* a better match than the unspecialized version? And if it's
not, why is the specialization ever being instantiated? I don't doubt
that it's something obvious, but it would be helpful if you explain it.

Thanks.

Best regards,

Tom


[ See http://www.gotw.ca/resources/clcm.htm for info about ]
[ comp.lang.c++.moderated. First time posters: Do this! ]
Back to top
AlbertSSj
Guest





PostPosted: Tue Sep 19, 2006 12:25 am    Post subject: Re: Template instantiation problem, take 2 Reply with quote

Quote:
This invokes (and thus instantiates) operator*( Vector<1
const&, Matrix<1, 1> const& ). The return type of this function
is Vector<0>. So instantiating this function triggers the
instantiation of Vector<0> (and the instantiation of Vector<0>'s
copy constructor, but that's no problem here).

Are you absolutely sure?

With a little modification, removing the array and adding a

std::cout << __PRETTY_FUNCTION__ << std::endl;

to the two functions, here is the output

Vector<WIDTH> operator*(const Vector<HEIGHT>&, const Matrix<HEIGHT,
WIDTH>&) [with int HEIGHT = 1, int WIDTH = 1]

So the return type is Vector<1>....

(As it should be...)


[ See http://www.gotw.ca/resources/clcm.htm for info about ]
[ comp.lang.c++.moderated. First time posters: Do this! ]
Back to top
loufoque
Guest





PostPosted: Tue Sep 19, 2006 12:30 am    Post subject: Re: Template instantiation problem, take 2 Reply with quote

kanze wrote :

Quote:
This invokes (and thus instantiates) operator*( Vector<1
const&, Matrix<1, 1> const& ). The return type of this function
is Vector<0>.

No, it is Vector<1>.

It seems you're confusing

Vector<1> operator*(Vector<1> const&, Matrix<1, 1> const&)
(first specialization with HEIGHT = 1, WIDTH = 1)

with

Vector<0> operator*(Vector<1> const&, Matrix<2, 1> const&)
(second specilization with HEIGHT = 2, WIDTH = 1)

or

Vector<0> operator*(Vector<0> const&, Matrix<1, 1> const&)
(second specialization with HEIGHT = 1, WIDTH = 1)

[ See http://www.gotw.ca/resources/clcm.htm for info about ]
[ comp.lang.c++.moderated. First time posters: Do this! ]
Back to top
Lars Jordan
Guest





PostPosted: Tue Sep 19, 2006 1:12 am    Post subject: Re: Template instantiation problem, take 2 Reply with quote

Quote:
So why does not this compile?

template <int N
struct Vector
{
int data_[N];
};

template <int HEIGHT, int WIDTH
struct Matrix
{
};

template <int HEIGHT, int WIDTH
Vector<WIDTH> operator *(
const Vector<HEIGHT>&,
const Matrix<HEIGHT, WIDTH>&)
{
return Vector<WIDTH>();
}

template <int HEIGHT, int WIDTH
Vector<WIDTH - 1> operator *(
const Vector<HEIGHT - 1>&,
const Matrix<HEIGHT, WIDTH>&)
{
return Vector<WIDTH - 1>();
}

int main()
{
Matrix<1, 1> transform;
Vector<1> translation;

translation = translation * transform;

This invokes (and thus instantiates) operator*( Vector<1
const&, Matrix<1, 1> const& ). The return type of this function
is Vector<0>. So instantiating this function triggers the
instantiation of Vector<0> (and the instantiation of Vector<0>'s
copy constructor, but that's no problem here).

As far as I interpret Wink this code snippet the instantiation of
operator*( Vector<1>, Matrix<1,1> ) returns Vector<1> - pls correct me.

But if this is correct then a zero-sized array shouldn't be the result.
What I wonder about is why VC8 chooses the second operator template
because looking at the parameter types I think it were a better match
if WIDTH and HEIGHT are equal, or am I missing something here?

Quote:

return 0;
}

Lars

[ See http://www.gotw.ca/resources/clcm.htm for info about ]
[ comp.lang.c++.moderated. First time posters: Do this! ]
Back to top
Joe
Guest





PostPosted: Tue Sep 19, 2006 2:00 am    Post subject: Re: Template instantiation problem, take 2 Reply with quote

Kaba wrote:
Quote:
Hello, I posted this problem to comp.lang.c++, but since I didn't get a
satisfying answer, I decided to post here.

Here is a short snippet of code that does not compile (tested with Vc8
and Comeau). This is because somehow Vector<0> gets instantiated, for
which the array size goes to 0. However, I don't quite get it why it
gets instantiated in the first place. So why does not this compile?


Code removed for brevity.

I compiled the code you posted in VC8 without problem. Are you using
some option that I should know about to cause it to fail?

joe


[ See http://www.gotw.ca/resources/clcm.htm for info about ]
[ comp.lang.c++.moderated. First time posters: Do this! ]
Back to top
Kaba
Guest





PostPosted: Tue Sep 19, 2006 3:23 am    Post subject: Re: Template instantiation problem, take 2 Reply with quote

Quote:
Code removed for brevity.

I compiled the code you posted in VC8 without problem. Are you using
some option that I should know about to cause it to fail?

With normal switches you should get a warning about 0-sized arrays. It
does compile and link however. If you switch off the Microsoft specific
language extensions, then you get an error.

--
Kalle Rutanen
http://kaba.hilvi.org

[ See http://www.gotw.ca/resources/clcm.htm for info about ]
[ comp.lang.c++.moderated. First time posters: Do this! ]
Back to top
Vladimir Marko
Guest





PostPosted: Tue Sep 19, 2006 3:25 am    Post subject: Re: Template instantiation problem, take 2 Reply with quote

Kaba wrote:
Quote:
Here is a short snippet of code that does not compile (tested with Vc8
and Comeau). This is because somehow Vector<0> gets instantiated, for
which the array size goes to 0. However, I don't quite get it why it
gets instantiated in the first place. So why does not this compile?

template <int N
struct Vector
{
int data_[N];
};

template <int HEIGHT, int WIDTH
struct Matrix
{
};

template <int HEIGHT, int WIDTH
Vector<WIDTH> operator *(
const Vector<HEIGHT>&,
const Matrix<HEIGHT, WIDTH>&)
{
return Vector<WIDTH>();
}

template <int HEIGHT, int WIDTH
Vector<WIDTH - 1> operator *(
const Vector<HEIGHT - 1>&,
const Matrix<HEIGHT, WIDTH>&)
{
return Vector<WIDTH - 1>();
}

int main()
{
Matrix<1, 1> transform;
Vector<1> translation;

translation = translation * transform;

return 0;
}

This is gonna be quite long as I'm going to explain the whole process
in detail. And I'm not going to look up the exact paragraphs in the
standard since they are many.

The line
translation = translation * transform;
triggers the lookup for operator* with function arguments
argument 1: Vector<1> l-value
argument 2: Matrix<1,1> l-value
The lookup finds both templated operator*s, and tries to find out
whether any of them is a match. That's where template argument
deduction comes to play. Each function parameter is compared to the
corresponding function argument to find the template arguments.

For the first operator* template, i.e.
template <int HEIGHT, int WIDTH>
Vector<WIDTH> operator *(
const Vector<HEIGHT>&,
const Matrix<HEIGHT, WIDTH>&);
from the first parameter-argument pair,
function parameter 1: const Vector<HEIGHT>&
function argument 1: Vector<1> l-value
the compiler deduces
template arguments: HEIGHT=1, WIDTH=unknown
and from the second parameter-argument pair,
function parameter 2: const Matrix<HEIGHT,WIDTH>&
function argument 2: Matrix<1,1> l-value
it deduces
template arguments: HEIGHT=1, WIDTH=1
Since these two _independent_ deductions gave compatible results, the
template arguments are deduced as HEIGHT=1, WIDTH=1. This "deduced
operator*" would then be
Vector<1> operator*(const Vector<1>&,const Matrix<1,1>&);
and it is a match.

For the second operator* template, i.e.
template <int HEIGHT, int WIDTH>
Vector<WIDTH - 1> operator *(
const Vector<HEIGHT - 1>&,
const Matrix<HEIGHT, WIDTH>&);
from the first parameter-argument pair,
function parameter 1: const Vector<HEIGHT-1>&
function argument 1: Vector<1> l-value
the compiler deduces
template arguments: HEIGHT=unknown, WIDTH=unknown
(if HEIGHT is used directly it can be deduced, if it's just a part of
an integral expression, it can't; that's the catch!)
and from the second parameter-argument pair,
function parameter 2: const Matrix<HEIGHT,WIDTH>&
function argument 2: Matrix<1,1> l-value
it deduces
template arguments: HEIGHT=1, WIDTH=1
We again got two compatible results (which may be quite unexpected), so
the template arguments are deduced as HEIGHT=1, WIDTH=1. The "deduced
operator*" would be
Vector<0> operator*(const Vector<0>&,const Matrix<1,1>&);
and the compiler must find out whether it is a match or not. The
question is whether a conversion exists
from argument: Vector<1> l-value
to parameter: const Vector<0>&
And in order to answer this question the compiler must look at the
constructors of Vector<0>, thus it instantiates it. This is where you
get an error.

Remark: The standard exactly specifies all cases where the substitution
failure results in deduction failure instead of an error (SFINAE). This
is not one of them! However, gcc behaves as if it was :(


Now, just for the fun of it let's see what happens if we add a template
specialization
template<>
struct Vector<0>{
Vector(Vector<1>&); // note the non-const reference!
};
We have a conversion constructor which convert the
function argument1: Vector<1> l-value
to a temporary Vector<0> object. So the second operator* template is a
match too. Is any of the operator* templates more specialized? Nope, we
get an ambiguity, because there is neither a conversion
from: const Vector<1>&
to: const Vector<0>&
nor
from: const Vector<0>&
to: const Vector<1>&
And that's where the Comeau Online joins gcc and incorrectly compiles
the code.

Cheers,
Mgr. Vladimir Marko


[ See http://www.gotw.ca/resources/clcm.htm for info about ]
[ comp.lang.c++.moderated. First time posters: Do this! ]
Back to top
David Abrahams
Guest





PostPosted: Tue Sep 19, 2006 9:58 pm    Post subject: Re: Template instantiation problem, take 2 Reply with quote

Kaba <none (AT) here (DOT) com> writes:

Quote:
Hello, I posted this problem to comp.lang.c++, but since I didn't get a
satisfying answer, I decided to post here.

Here is a short snippet of code that does not compile (tested with Vc8
and Comeau). This is because somehow Vector<0> gets instantiated, for
which the array size goes to 0. However, I don't quite get it why it
gets instantiated in the first place. So why does not this compile?

template <int N
struct Vector
{
int data_[N];
};

template <int HEIGHT, int WIDTH
struct Matrix
{
};

template <int HEIGHT, int WIDTH
Vector<WIDTH> operator *(
const Vector<HEIGHT>&,
const Matrix<HEIGHT, WIDTH>&)
{
return Vector<WIDTH>();
}

template <int HEIGHT, int WIDTH
Vector<WIDTH - 1> operator *(
const Vector<HEIGHT - 1>&,
const Matrix<HEIGHT, WIDTH>&)
{
return Vector<WIDTH - 1>();
}

int main()
{
Matrix<1, 1> transform;
Vector<1> translation;

translation = translation * transform;

return 0;
}

The problem here is that even though the 2nd overload doesn't match,
in order to determine that it's a non-match it needs to instantiate
the argument types. The second overload is "more specialized" than
the first (see the partial ordering algorithm in the standard), so if
the compiler starts trying to match with the last argument, it gets
HEIGHT == 1 and WIDTH == 1. Then it needs to see whether the first
argument, a Vector<1> lvalue, matches Vector<0> const&. You might
think it obviously doesn't, but consider this definition of Vector:

template <int N>
struct Vector
{
Vector();
Vector(Vector<N+1> const&);
int data_[N > 0 ? N : 1];
};

In this case it would be a match. The upshot is that the compiler
needs to instantiate the entire definition of Vector<0> (including the
declarations of its members) in order to rule out the 2nd overload.

You can work around this issue by replacing the 2nd overload with:

template <int height_minus_1, int WIDTH>
Vector<WIDTH - 1> operator *(
const Vector<height_minus_1>&,
const Matrix<height_minus_1 + 1, WIDTH>&)
{
return Vector<WIDTH - 1>();
}

HTH,

--
Dave Abrahams
Boost Consulting
www.boost-consulting.com

[ See http://www.gotw.ca/resources/clcm.htm for info about ]
[ comp.lang.c++.moderated. First time posters: Do this! ]
Back to top
Greg Herlihy
Guest





PostPosted: Tue Sep 19, 2006 10:05 pm    Post subject: Re: Template instantiation problem, take 2 Reply with quote

Vladimir Marko wrote:
Quote:
Kaba wrote:
Here is a short snippet of code that does not compile (tested with Vc8
and Comeau). This is because somehow Vector<0> gets instantiated, for
which the array size goes to 0. However, I don't quite get it why it
gets instantiated in the first place. So why does not this compile?

template <int N
struct Vector
{
int data_[N];
};

template <int HEIGHT, int WIDTH
struct Matrix
{
};

template <int HEIGHT, int WIDTH
Vector<WIDTH> operator *(
const Vector<HEIGHT>&,
const Matrix<HEIGHT, WIDTH>&)
{
return Vector<WIDTH>();
}

template <int HEIGHT, int WIDTH
Vector<WIDTH - 1> operator *(
const Vector<HEIGHT - 1>&,
const Matrix<HEIGHT, WIDTH>&)
{
return Vector<WIDTH - 1>();
}

int main()
{
Matrix<1, 1> transform;
Vector<1> translation;

translation = translation * transform;

return 0;
}

This is gonna be quite long as I'm going to explain the whole process
in detail. And I'm not going to look up the exact paragraphs in the
standard since they are many.

The line
translation = translation * transform;
triggers the lookup for operator* with function arguments
argument 1: Vector<1> l-value
argument 2: Matrix<1,1> l-value
The lookup finds both templated operator*s, and tries to find out
whether any of them is a match. That's where template argument
deduction comes to play. Each function parameter is compared to the
corresponding function argument to find the template arguments.

....

For the second operator* template, i.e.
template <int HEIGHT, int WIDTH
Vector<WIDTH - 1> operator *(
const Vector<HEIGHT - 1>&,
const Matrix<HEIGHT, WIDTH>&);
from the first parameter-argument pair,
function parameter 1: const Vector<HEIGHT-1>&
function argument 1: Vector<1> l-value
the compiler deduces
template arguments: HEIGHT=unknown, WIDTH=unknown
(if HEIGHT is used directly it can be deduced, if it's just a part of
an integral expression, it can't; that's the catch!)
and from the second parameter-argument pair,
function parameter 2: const Matrix<HEIGHT,WIDTH>&
function argument 2: Matrix<1,1> l-value
it deduces
template arguments: HEIGHT=1, WIDTH=1
We again got two compatible results (which may be quite unexpected), so
the template arguments are deduced as HEIGHT=1, WIDTH=1. The "deduced
operator*" would be
Vector<0> operator*(const Vector<0>&,const Matrix<1,1>&);
and the compiler must find out whether it is a match or not. The
question is whether a conversion exists

Actually, the first template argument in the second function cannot be
deduced because the non-type parameter is involved in an expression. In
other words, Vector<HEIGHT> can be deduced but Vector<HEIGHT-1> (or any
expression involving HEIGHT) cannot be deduced:

"If, in the declaration of a function template with a non-type template
parameter, the non-type template parameter is used in an expression in
the function parameter list, the expression is a non-deduced context."
[§14.8.2.5/14]

The example provided:

template <int i> class A { / * ... */ };
template <int i> void g(A<i+1>);
template <int i> void f(A<i>, A<i+1>);

A<1> a1;
g(a1); // error: deduction fails for expression i+1

applies to this case as well.

Since the template argument cannot be deduced, the compiler
instantiates the second, overloaded operator*() as a candidate
function, which in turn requires instantiating Vector<0>. This
instantiation fails due to an illegal member declaration (a member
array of size zero).

Quote:
Remark: The standard exactly specifies all cases where the substitution
failure results in deduction failure instead of an error (SFINAE). This
is not one of them! However, gcc behaves as if it was Sad

The original program fails to compile on gcc 4.01 when I tested it, so
at least some builds of gcc are correct.

In any event, the failure in this case occurs before the substitution
can even be attempted. Moreover the failure occurs during instantiation
(that is after, an instantiation has begun) - which is always an error:

"The program is ill-formed if any instantiation fails." [§2.1/8]

Now once the program is corrected and Vector<0> is made instantiable -
then the attempted substitution of Vector<0> as the function parameter
does fail. And the substitution failure is not an error.

Greg


[ See http://www.gotw.ca/resources/clcm.htm for info about ]
[ comp.lang.c++.moderated. First time posters: Do this! ]
Back to top
kanze
Guest





PostPosted: Tue Sep 19, 2006 10:18 pm    Post subject: Re: Template instantiation problem, take 2 Reply with quote

Lars Jordan wrote:

Quote:
This invokes (and thus instantiates) operator*( Vector<1
const&, Matrix<1, 1> const& ). The return type of this
function is Vector<0>. So instantiating this function
triggers the instantiation of Vector<0> (and the
instantiation of Vector<0>'s copy constructor, but that's no
problem here).

As far as I interpret Wink this code snippet the instantiation
of operator*( Vector<1>, Matrix<1,1> ) returns Vector<1> - pls
correct me.

Yes, I mixed the two operators, taking the return type from one,
and the parameters from the other.

Quote:
But if this is correct then a zero-sized array shouldn't be
the result. What I wonder about is why VC8 chooses the second
operator template because looking at the parameter types I
think it were a better match if WIDTH and HEIGHT are equal, or
am I missing something here?

Apparently, the compiler is trying to instantiate both, then do
overload resolution. The compiler does have to instantiate the
function declaration in order to do overload resolution. In
this particular case, at first view (well, second, since I
screwed up the first view), I would say that template argument
deduction should fail for the first function, because it
requires two different values for HEIGHT. So I think that
SFINAE should kick in (and make the code legal). But I'm not
sure. I'm never really sure when SFINAE is supposed to kick in.

--
James Kanze GABI Software
Conseils en informatique orientée objet/
Beratung in objektorientierter Datenverarbeitung
9 place Sémard, 78210 St.-Cyr-l'École, France, +33 (0)1 30 23 00 34


[ See http://www.gotw.ca/resources/clcm.htm for info about ]
[ comp.lang.c++.moderated. First time posters: Do this! ]
Back to top
Vladimir Marko
Guest





PostPosted: Wed Sep 20, 2006 4:15 am    Post subject: Re: Template instantiation problem, take 2 Reply with quote

Greg Herlihy wrote:
Quote:
Vladimir Marko wrote:
[...]
For the second operator* template, i.e.
template <int HEIGHT, int WIDTH
Vector<WIDTH - 1> operator *(
const Vector<HEIGHT - 1>&,
const Matrix<HEIGHT, WIDTH>&);
from the first parameter-argument pair,
function parameter 1: const Vector<HEIGHT-1>&
function argument 1: Vector<1> l-value
the compiler deduces
template arguments: HEIGHT=unknown, WIDTH=unknown
(if HEIGHT is used directly it can be deduced, if it's just a part of
an integral expression, it can't; that's the catch!)
and from the second parameter-argument pair,
function parameter 2: const Matrix<HEIGHT,WIDTH>&
function argument 2: Matrix<1,1> l-value
it deduces
template arguments: HEIGHT=1, WIDTH=1
We again got two compatible results (which may be quite unexpected), so
the template arguments are deduced as HEIGHT=1, WIDTH=1. The "deduced
operator*" would be
Vector<0> operator*(const Vector<0>&,const Matrix<1,1>&);
and the compiler must find out whether it is a match or not. The
question is whether a conversion exists

Actually, the first template argument in the second function cannot be
deduced because the non-type parameter is involved in an expression. In
other words, Vector<HEIGHT> can be deduced but Vector<HEIGHT-1> (or any
expression involving HEIGHT) cannot be deduced:

[snip §14.8.2.5/14 + example]


Let me rephrase what _I_ wrote using _your_ language:

Actually, the first template argument in the second function cannot be
deduced _from_the_first_paremeter-argument_pair_ because the non-type
parameter is involved in an expression. (See also §14.8.2.4/2)

Quote:
Since the template argument cannot be deduced, the compiler
instantiates the second, overloaded operator*() as a candidate
function, which in turn requires instantiating Vector<0>. This
instantiation fails due to an illegal member declaration (a member
array of size zero).

Am I too tired to understand? Either the template _can_ be deduced
(from the second P/A pair; as I originally wrote) and the function
declaration _is_ instantiated; or the template argument _cannot_
be deduced (as you wrote) and the function declaration _is_not_
instantiated at all (making your statement false).

Btw., instantiating a function _declaration_ using Vector<0>
_does_not_ instantiate Vector<0>.

Quote:
Remark: The standard exactly specifies all cases where the substitution
failure results in deduction failure instead of an error (SFINAE). This
is not one of them! However, gcc behaves as if it was :(

The original program fails to compile on gcc 4.01 when I tested it, so
at least some builds of gcc are correct.

gcc-3.3 - fails to compile
gcc-4.0.1 - fails to compile
gcc-4.1.1 - compiles

Quote:
In any event, the failure in this case occurs before the substitution
can even be attempted. Moreover the failure occurs during instantiation
(that is after, an instantiation has begun) - which is always an error:

"The program is ill-formed if any instantiation fails." [§2.1/8]

I must admit that my remark is a little off-topic because...

In any event, the failure in this case occurs _after_ the substitution
has already been performed.

Quote:
Now once the program is corrected and Vector<0> is made instantiable -
then the attempted substitution of Vector<0> as the function parameter
does fail. And the substitution failure is not an error.

How does the substitution of Vector<0> as the function parameter
fail? You can declare functions with non-instantiable parameter
types all day long and as long as no definition is provided (or
instantiated in case of function templates) the program can be
well-formed. The exception is when you provide a reason for the
parameter instantiation, say forcing the compiler to look for
a conversion constructor.

Cheers,
Mgr. Vladimir Marko


[ See http://www.gotw.ca/resources/clcm.htm for info about ]
[ comp.lang.c++.moderated. First time posters: Do this! ]
Back to top
Keith H Duggar
Guest





PostPosted: Wed Sep 20, 2006 8:11 pm    Post subject: Re: Template instantiation problem, take 2 Reply with quote

Vladimir Marko wrote:
Quote:
if HEIGHT is used directly it can be deduced, if it's just
a part of an integral expression, it can't; that's the
catch!)

Greg Herlihy wrote:
Quote:
"If, in the declaration of a function template with a
non-type template parameter, the non-type template
parameter is used in an expression in the function
parameter list, the expression is a non-deduced context."
[§14.8.2.5/14]

Out of curiosity, is this limitation imposed because
deduction from expressions might require the compiler to
solve arbitrarily complex algebraic equations? For example
a quadratic version of the template in question:

template <int HEIGHT, int WIDTH>
Vector<HEIGHT*HEIGHT - 3*HEIGHT + 3> operator *(
const Vector<HEIGHT*HEIGHT - 3*HEIGHT + 3>&,
const Matrix<HEIGHT, WIDTH>&)
{
return Vector<HEIGHT*HEIGHT - 3*HEIGHT + 3>();
}

when called with Vector<1> would require the compiler solve
for HEIGHT = 1 or HEIGHT = 2? Likewise it would have to fail
for Vector<2> since there is no integer solution.

-- Keith -- Fraud 6


[ See http://www.gotw.ca/resources/clcm.htm for info about ]
[ comp.lang.c++.moderated. First time posters: Do this! ]
Back to top
David Abrahams
Guest





PostPosted: Wed Sep 20, 2006 9:50 pm    Post subject: Re: Template instantiation problem, take 2 Reply with quote

"Keith H Duggar" <duggar (AT) alum (DOT) mit.edu> writes:

Quote:
Vladimir Marko wrote:
if HEIGHT is used directly it can be deduced, if it's just
a part of an integral expression, it can't; that's the
catch!)

Greg Herlihy wrote:
"If, in the declaration of a function template with a
non-type template parameter, the non-type template
parameter is used in an expression in the function
parameter list, the expression is a non-deduced context."
[§14.8.2.5/14]

Out of curiosity, is this limitation imposed because
deduction from expressions might require the compiler to
solve arbitrarily complex algebraic equations?

It's both worse and simpler than that. In principle there may be no
way to deduce the template parameter value:

template <int N>
void f(vector<N/2>);

f(vector<3>()); // Is N 6 or 7?

--
Dave Abrahams
Boost Consulting
www.boost-consulting.com

[ See http://www.gotw.ca/resources/clcm.htm for info about ]
[ comp.lang.c++.moderated. First time posters: Do this! ]
Back to top
Display posts from previous:   
Post new topic   Reply to topic    C++Talk.NET Forum Index -> C++ Language (Moderated) All times are GMT
Goto page 1, 2  Next
Page 1 of 2

 
Jump to:  
You cannot post new topics in this forum
You cannot reply to topics in this forum
You cannot edit your posts in this forum
You cannot delete your posts in this forum
You cannot vote in polls in this forum


Powered by phpBB © 2001, 2006 phpBB Group
SEO toolkit © 2004-2006 webmedic.