I found a strange issue when porting my code from Visual Studio to gcc. The following code compiles fine in Visual Studio, but results in an error in gcc.
namespace Baz
{
template <class T>
class Foo
{
public:
void Bar()
{
Baz::Print();
}
};
void Print() { std::cout << "Hello, world!" << std::endl; }
}
int main()
{
Baz::Foo<int> foo;
foo.Bar();
return 0;
}
My understanding is that this should compile OK, as the class shouldn’t be compiled until the template is instantiated (which is after Print() is defined). However, gcc reports the following:
t.cpp: In member function ‘void Baz::Foo::Bar()’:
Line 8: error: ‘Print’ is not a member of ‘Baz’
Who’s right? And if gcc is right, why?
gcc is right. It is because
Bazis a namespace and namespaces are parsed top to bottom, so the declaration ofBaz::Printis not visible from insideFoo(since it is beneath it).When the template is instantiated, only names visible from the template definition are considered, not counting Koenig lookup (which wouldn’t change anything in your case).
If
Bazwere a struct or class, your code would work, since these are parsed in two phases (first declarations, then bodies), so anything declared in a struct or class is visible inside eg. member functions, regardles of their order in the source file.You can make it work by declaring
Baz::PrintbeforeFoo.Quoting the standard:
14.6.3 Non-dependent names
Non-dependent names used in a template definition are found using the usual name lookup and bound at the
point they are used.
14.6.4 Dependent name resolution
In resolving dependent names, names from the following sources are considered:
from the instantiation context (14.6.4.1) and from the definition context.
(end quotation)
When
Printis nondependent (as it is now), it wouldn’t be found since it is looked up before its declaration (in the template definition context). If it were dependent, it wouldn’t be the first case (same as when nondependent), andBazis not associated with int (the template parameter) in any way, so it wouldn’t be searched according to the second case either.