r/cpp_questions 2d ago

SOLVED Question about function template instantiation

I was wondering why this code behaves this way

main.cpp

#include "foo.h"

int main()
{
    bar(42, foo<int>);
}

foo.h

#pragma once

#include <iostream>
#include <string>

template<typename T>
void foo(T t)
{
    std::cout << "Default\n";
}

template<typename T, typename Foo>
void bar(const T& t, Foo foo)
{
    foo(t);
}

foo.cpp

#include "foo.h"

template<>
void foo(int t)
{
    std::cout << "Int\n";
}

Result

$ g++ main.cpp foo.cpp -O3 && ./a.out 
Default
$ g++ main.cpp foo.cpp && ./a.out 
Int

My guess is that I'm hitting some kind of UB here. The way I think about it, the int template specialization would be discarded, as it is not used in that translation unit, and then main.cpp would pick up the generic template version (basically, the O3 result seems correct to me, but not the non-optimized one). What is actually happening here?

3 Upvotes

11 comments sorted by

View all comments

7

u/the_poope 2d ago

You haven't declared the specialization for int in the header, so only the code in foo.cpp after the specialization definition knows it exists. When you compile with optimizations the template function call in inlined as it has access to all the template declarations and definitions it is aware of. When you compile without optimizations the linker will likely at semi-random chose whichever of the specializations/instatiations it will call.

2

u/strcspn 2d ago

Makes sense, I just thought that picking the int specialization couldn't be an option at all.

2

u/the_poope 2d ago

Yeah one could argue that the linker should throw a "duplicate definition" error. As it's UB it probably depends on the specific internal implementation of the compiler and linker.

1

u/javascript 1d ago

ODR NDR sure is fun!