partial ordering of template functions & parameter specification

M

Marek Vondrak

Hello.

I have written the following program and am curious why it prints "1" "2".
What are the exact effects of explicitly providing function template
parameters at the call? Is the second assign() function really a
specialization of the first assign() or is it an assign() overload?

Thank you.
-- Marek

-- cut --
#include <iostream>

class O { };
class M { };

template <class Left, class Right>
class Plus { };

template <class Left, class Right, class Op>
int assign( Left & left, const Right & right, const Op & op )
{
return 1;
}

template <class Op>
int assign( M & left, const Plus<M, M> & right, const Op & op )
{
return 2;
}

int main()
{
M m;

std::cout << assign<M, Plus<M, M>, O>( m, Plus<M, M>(), O() ) <<
std::endl;
std::cout << assign( m, Plus<M, M>(), O() ) << std::endl;
}
-- cut --
 
A

amparikh

Marek said:
Hello.

I have written the following program and am curious why it prints "1" "2".
What are the exact effects of explicitly providing function template
parameters at the call? Is the second assign() function really a
specialization of the first assign() or is it an assign() overload?

Thank you.
-- Marek

-- cut --
#include <iostream>

class O { };
class M { };

template <class Left, class Right>
class Plus { };

template <class Left, class Right, class Op>
int assign( Left & left, const Right & right, const Op & op )
{
return 1;
}

template <class Op>
int assign( M & left, const Plus<M, M> & right, const Op & op )
{
return 2;
}

int main()
{
M m;

std::cout << assign<M, Plus<M, M>, O>( m, Plus<M, M>(), O() ) <<
std::endl;
std::cout << assign( m, Plus<M, M>(), O() ) << std::endl;
}
-- cut --

Based on reading the relevant section from Vandervoorde/Josuttis book,
the second assign function would be more specialized than the first
function and therefore, when explicity providing parameters, the second
one is selected.
 
M

Marek Vondrak

Marek said:
Hello.

I have written the following program and am curious why it prints "1"
"2".
What are the exact effects of explicitly providing function template
parameters at the call? Is the second assign() function really a
specialization of the first assign() or is it an assign() overload?

Thank you.
-- Marek

-- cut --
#include <iostream>

class O { };
class M { };

template <class Left, class Right>
class Plus { };

template <class Left, class Right, class Op>
int assign( Left & left, const Right & right, const Op & op )
{
return 1;
}

template <class Op>
int assign( M & left, const Plus<M, M> & right, const Op & op )
{
return 2;
}

int main()
{
M m;

std::cout << assign<M, Plus<M, M>, O>( m, Plus<M, M>(), O() ) <<
std::endl; // [1]
std::cout << assign( m, Plus<M, M>(), O() ) << std::endl; // [2]
}
-- cut --

Based on reading the relevant section from Vandervoorde/Josuttis book,
the second assign function would be more specialized than the first
function and therefore, when explicity providing parameters, the second
one is selected.

This is what I would intuitively expect to happen but both G++ and MSVC
behave just opposite. If template parameters are specified explicitly, the
first assign function is called at [1] despite the fact that the second
assign function is more specialized. If template parameters are not
specified and are deduced by the compiler ([2]), the more specialized
function is called as expected.

Can anyone explain why is this happening?

-- Marek
 
M

Marek Vondrak

This is what I would intuitively expect to happen but both G++ and MSVC
behave just opposite.

Sorry, I did not read the follow up properly. Correction: I would expect the
program to print "2" "2" (the specialized assign should be called in both
the cases, regardless of whether template parameters are specified or not).
-- Marek
 
J

Jonathan Mcdougall

Marek said:
Hello.

I have written the following program and am curious why it prints "1" "2".
What are the exact effects of explicitly providing function template
parameters at the call? Is the second assign() function really a
specialization of the first assign() or is it an assign() overload?

Thank you.
-- Marek

-- cut --
#include <iostream>

class O { };
class M { };

template <class Left, class Right>
class Plus { };

template <class Left, class Right, class Op>
int assign( Left & left, const Right & right, const Op & op )
{
return 1;
}

template <class Op>
int assign( M & left, const Plus<M, M> & right, const Op & op )
{
return 2;
}

int main()
{
M m;

std::cout << assign<M, Plus<M, M>, O>( m, Plus<M, M>(), O() ) <<

Well this surely cannot use the template with one parameter since you
are specifying three of them. That must print 1.
std::cout << assign( m, Plus<M, M>(), O() ) << std::endl;

This will prefer the template with one parameter. The compiler will
always select the most specialized template if it has a choice. This
must print 2.


Jonathan
 
M

Maxim Yegorushkin

Marek said:
Hello.

I have written the following program and am curious why it prints "1" "2".
What are the exact effects of explicitly providing function template
parameters at the call? Is the second assign() function really a
specialization of the first assign() or is it an assign() overload?

Thank you.
-- Marek

-- cut --
#include <iostream>

class O { };
class M { };

template <class Left, class Right>
class Plus { };

template <class Left, class Right, class Op>
int assign( Left & left, const Right & right, const Op & op )
{
return 1;
}

template <class Op>
int assign( M & left, const Plus<M, M> & right, const Op & op )
{
return 2;
}

int main()
{
M m;

std::cout << assign<M, Plus<M, M>, O>( m, Plus<M, M>(), O() ) <<
std::endl;
std::cout << assign( m, Plus<M, M>(), O() ) << std::endl;
}

assign function templates are disparate function templates. There is no
partial template specialization for functions. The first function
template has three template arguments and the second has one. Therefore
the second function template can not be used with three template
arguments specified as you do.
 
M

Marek Vondrak

Hello.
assign function templates are disparate function templates. There is no
partial template specialization for functions.

Really? I think this was true in the prestandard era. Since C++98 there is a
partial specialization of functions and partional ordering rules.
The first function
template has three template arguments and the second has one. Therefore
the second function template can not be used with three template
arguments specified as you do.

Although I see the rationale behind your explanation, please consider the
following program.

class O { };
class M { };

template <class Left, class Right>
class Plus { };

// AS1
template <class Left, class Right, class Op>
void assign( Left & left, const Right & right, const Op & op ) { } //
Primary template

// AS2
template <>
void assign( M & left, const Plus<M, M> & right, const O & op ) { } //
Explicit specialization of AS1

int main()
{
M m;

assign<M, Plus<M, M>, O>( m, Plus<M, M>(), O() ); // Calls AS2
}

Why does it call AS2? It occurs to me, that AS1 is treated as the primary
template and AS2 as its explicit specialization. In the same sense I would
then believe that in the original program the first assign is the primary
template and the second assign its partial specialization:

template <class Left, class Right>
class Plus { };

// AS1
template <class Left, class Right, class Op>
void assign( Left & left, const Right & right, const Op & op ) { } //
Primary template again.

// AS2
template <class Op>
void assign( M & left, const Plus<M, M> & right, const Op & op ) { } //
Should be partial specialization of AS1?

int main()
{
M m;

assign<M, Plus<M, M>, O>( m, Plus<M, M>(), O() ); // Calls AS1! Why?
This is inconsistent with the explicit specialization example!
}

-- Marek
 
M

Maxim Yegorushkin

Marek said:
Really? I think this was true in the prestandard era. Since C++98 there is a
partial specialization of functions and partional ordering rules.

I repeat. There is no *partial* specialization for function templates.
Although I see the rationale behind your explanation, please consider the
following program.

class O { };
class M { };

template <class Left, class Right>
class Plus { };

// AS1
template <class Left, class Right, class Op>
void assign( Left & left, const Right & right, const Op & op ) { } //
Primary template

// AS2
template <>
void assign( M & left, const Plus<M, M> & right, const O & op ) { } //
Explicit specialization of AS1

int main()
{
M m;

assign<M, Plus<M, M>, O>( m, Plus<M, M>(), O() ); // Calls AS2
}

Why does it call AS2? It occurs to me, that AS1 is treated as the primary
template and AS2 as its explicit specialization.

AS2 is a *full* function template specialization because it has no
template arguments.
In the same sense I would
then believe that in the original program the first assign is the primary
template and the second assign its partial specialization:

Your belief is premised on a false assumption that there exists partial
function template specialization.
 
M

Marek Vondrak

I repeat. There is no *partial* specialization for function templates.
Your belief is premised on a false assumption that there exists partial
function template specialization.

Okay, thanks Maxim and sorry for my doubts. I thought partial specialization
for function templates was supported. That is why I originally asked whether
the second assign() was actually a *specialization* or an *overload* of the
first assign. I also asked in comp.lang.c++.moderated and was luckily
provided with links to relevant articles. Now, it should be clear. Thanks
for help.

-- Marek
 
M

Marek Vondrak

assign function templates are disparate function templates. There is no
partial template specialization for functions.

Really? I think this was true in the prestandard era. Since C++98 there is a
partial specialization of functions and partional ordering rules.
The first function
template has three template arguments and the second has one. Therefore
the second function template can not be used with three template
arguments specified as you do.

Although I see the rationale behind your explanation, please consider the
following program.

class O { };
class M { };

template <class Left, class Right>
class Plus { };

// AS1
template <class Left, class Right, class Op>
void assign( Left & left, const Right & right, const Op & op ) { } //
Primary template

// AS2
template <>
void assign( M & left, const Plus<M, M> & right, const O & op ) { } //
Explicit specialization of AS1

int main()
{
M m;

assign<M, Plus<M, M>, O>( m, Plus<M, M>(), O() ); // Calls AS2
}

Why does it call AS2? It occurs to me, that AS1 is treated as the primary
template and AS2 as its explicit specialization. In the same sense I would
then believe that in the original program the first assign is the primary
template and the second assign its partial specialization:

template <class Left, class Right>
class Plus { };

// AS1
template <class Left, class Right, class Op>
void assign( Left & left, const Right & right, const Op & op ) { } //
Primary template again.

// AS2
template <class Op>
void assign( M & left, const Plus<M, M> & right, const Op & op ) { } //
Should be partial specialization of AS1?

int main()
{
M m;

assign<M, Plus<M, M>, O>( m, Plus<M, M>(), O() ); // Calls AS1! Why?
This is inconsistent with the explicit specialization example!
}

-- Marek



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

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
473,744
Messages
2,569,484
Members
44,903
Latest member
orderPeak8CBDGummies

Latest Threads

Top