Think you know C++?

Questions of the day. Answer without compiling and running (assuming your compiler gets it right). In each case, the question is "what is the output of the following program?"

Program 1.
1
2
3
4
5
6
7
8
9
10
11
12
#include <iostream>

template< typename U, typename T >
void g( U u, T t ) { f( u, t ); }

template< typename U, typename T >
void f( U, T ) { std::cout << "A" << std::endl; }

template< typename U >
void f( U, int ) { std::cout << "B" << std::endl; }

int main() { g( 42, 37 ); }


Program 2.
1
2
3
4
5
6
7
8
9
10
11
12
#include <iostream>

template< typename U, typename T >
void f( U, T ) { std::cout << "A" << std::endl; }

template< typename U, typename T >
void g( U u, T t ) { f( u, t ); }

template< typename U >
void f( U, int ) { std::cout << "B" << std::endl; }

int main() { g( 42, 37 ); }


Program 3.
1
2
3
4
5
6
7
8
9
10
11
12
#include <iostream>

template< typename U, typename T >
void f( U, T ) { std::cout << "A" << std::endl; }

template< typename U >
void f( U, int ) { std::cout << "B" << std::endl; }

template< typename U, typename T >
void g( U u, T t ) { f( u, t ); }

int main() { g( 42, 37 ); }


And then the final question ... Why are the answers what they are????
Last edited on
I'm prety sure the order is:

1. Error (f not defined)
2. A (defined before the other f())
3. Error (function parameter/name clash)
I smell a trick question here. Here's my guess:

1) error ("f not defined") as PiMaster suggested
2) "B"
3) "B"

The reason for 2 and 3:

- g(42,37); instantiates g with U=int and T=int
- g<int,int> calls f(U,int) with U=int because the most-specialized overload is always preferred when templates are involved.

The order in which g and f are declared is irrelevent as long as both versions of f are defined before g is instantiated. When it is declared is unimportant.

The compiler only needs to know f exists before g is defined to avoid the compiler error.

However in both cases 2 and 3, both versions of f are full defined when g is instantiated, which means the specialized version would be preferred.



Do I pass? lol

EDIT: Also this is fun. We need more topics like this.
Last edited on
Wow...I...totally missed the f not defined thing >_> I guess I fail C++. XD
14.5.5.2 [temp.func.order] ?
closed account (z05DSL3A)
I am going to say:
1: B it uses the most specialised when it finds out what it is
2: A it uses the most specialised at the point of calling
3: B it uses the most specialised at the point of caling


Last edited on
Kudos to Grey Wolf, who got all the answers right, although the reasoning isn't quite right, because
none of the programs use function template specialization, which would be denoted by
"template<> void f<...", and C++ does not currently support partial function template specialization
anyway.

Now, how about these? Same question: What is the output of the following programs, and why?

Program 1.
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
#include <iostream>

template< typename U, typename T >
void g( U u, T t ) { Foo<U,T>::g( u, t ); }

template< typename U, typename T >
struct Foo {
    static void g( U, T ) { std::cout << "A" << std::endl; }
};

template< typename U >
struct Foo<U, int> {
    static void g( U, int ) { std::cout << "B" << std::endl; }
};

int main() { g( 42, 37 ); }



Program 2.
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
#include <iostream>

template< typename U, typename T >
struct Foo {
    static void g( U, T ) { std::cout << "A" << std::endl; }
};

template< typename U, typename T >
void g( U u, T t ) { Foo<U,T>::g( u, t ); }

template< typename U >
struct Foo<U, int> {
    static void g( U, int ) { std::cout << "B" << std::endl; }
};

int main() { g( 42, 37 ); }




Program 3.
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
#include <iostream>

template< typename U, typename T >
struct Foo {
    static void g( U, T ) { std::cout << "A" << std::endl; }
};

template< typename U >
struct Foo<U, int> {
    static void g( U, int ) { std::cout << "B" << std::endl; }
};

template< typename U, typename T >
void g( U u, T t ) { Foo<U,T>::g( u, t ); }

int main() { g( 42, 37 ); }

Last edited on
closed account (z05DSL3A)
although the reasoning isn't quite right, because none of the programs use function template specialization

I must have my terminology mixed up. I'm thinking in terms of template instantiation, the generated functions being called generated specialisations (programmer written ones being explicit specialisations).

Edit:
Should I have said overload resolution? The first stage of overload resolution is to look at the available specialisations (as above) in the case of the second one, it has one available that fits the bill so uses it.

Edit 2:
Re: the second set, I don't think any of them would compile but it's midnight and I need my bed.
Last edited on
closed account (z05DSL3A)
After five hours sleep...I would still say the second lot would not compile because of a missing semicolon and missing template argument list but I not sure that that is what you are getting at. I have a feeling that the second definition of Foo::g() would always hide the first thus needing the argument list to call it. But if you put in the argument list I would expect that it would output B in all casses anyway.

PS. I find template functions much less confusing, template classes make me keep second guessing what is going on and addle my brain...Time for Coffee.
Ooops, sorry. I did not mean to have compile errors in there. I've fixed them above.

The second definition of g() doesn't hide the first since there is no inheritance involved. Rather, I've created
a partial specialization of Foo.

Since nobody else ventured an answer, you are again right -- B is output in all cases.

The moral to the story is that in the first set of programs, the order of declaration, matters, and in the
second set, it does not. The reason?

Well, it's sorta complicated. First, you have to come to grips with the fact that in the first set of programs,
the second declaration of f is neither a specialization nor an overload candidate of the first. That said,
when the compiler sees the implementation of g() calling f() [which is at the point of g()'s implementation,
not at the point of g()'s instantiation in main], in the first program the compiler has not seen any f() declarations
yet, so it doesn't know what to call yet. But in the second program, it has already seen the first f(), and since that
absolutely matches the calling syntax of f() required by g(), it knows to call the first f() regardless of U and T. In
the third program, it has seen both f()'s by the time g() is parsed, so again, the compiler cannot know definitively
which one to call until g() is actually instantiated. Which means that if T is int, then the second f() will get called
since it is a better match according to the C++ matching rules.

Yes, the C++ standard was specifically written this way.

So... why does the second set of programs always output B, then? Because here, I have partially specialized Foo.
Note that in the first set of programs, f is NOT specialized according to the C++ standard. This specialization is
how we expect the compiler to behave, even in the first case. But it does not, and deliberately so.

Here is a nice link to a good explanation of this behavior:
http://www.gotw.ca/publications/mill17.htm

The reason I posted this was because I just fixed this bug -- my code was implemented using template functions
(progs 1-3) and the first f() was being called when I expected the second one to be called. It turns out that GCC 3.3
got this wrong, so my code was working because two wrongs indeed make a right in the case. When I upgraded
to GCC 4.x, my code stopped working, and it took quite a while to narrow this down, and to cement in my mind
that this was indeed my bug and not a compiler bug.

So Grey Wolf, use template functions with care, unless the behavior of the compiler wrt template functions
makes perfect sense to you. I know that it didn't to me at first.


http://www.gotw.ca/publications/mill17.htm
closed account (z05DSL3A)
Maybe I'll read C++ Templates: The Complete Guide again it's been a few years since I last read it. Though I don't particularly like Templates, it was an interesting exercise.
Topic archived. No new replies allowed.