Why can I call function templates without forward declarations? - c++

If a normal function calls a function that has not been declared yet, I get a compile-time error:
void foo(int x)
{
bar(x); // ERROR: bar has not been declared yet
}
void bar(int x)
{
std::cout << x << '\n';
}
int main()
{
foo(42);
}
The fix is to either forward-declare the called function, or to switch the order of definitions.
However, these fixes do not seem to be necessary with function templates:
template<typename T>
void foo(T x)
{
bar(x); // OKAY
}
template<typename T>
void bar(T x)
{
std::cout << x << '\n';
}
int main()
{
foo(42);
}
This compiles just fine. Why is that? When the compiler sees bar(x), why does it not complain?
(I am using g++ 4.6.3)

This is a "why is the sky made out of bricks" type question. Ie, a question that asks why something false is true. It is not the case that in C++ your code is legal.
Live example, as you can see in gcc 4.8 this does not actually compile.
I guess the question "why does gcc 4.6 let this code compile" remains. One of the things that compilers did early on when writing template expanders was to treat them as something similar to macros. Very little would be done when they where declared, and everything would be looked up when they where instantiated.
Compilers now tend to do more thing when the template is declared, and less when it is instantiated. This is what the C++ standard requires, or is at least closer.
As it happens, ADL can get around this: bar lookups that find bar via ADL do not have to be visible at the point where foo is written, but rather at the point of instantiation.
The gcc 4.8 error message is pretty self explanatory:
prog.cpp: In instantiation of ‘void foo(T) [with T = int]’:
prog.cpp:16:7: required from here
prog.cpp:6:10: error: ‘bar’ was not declared in this scope, and no declarations were found by argument-dependent lookup at the point of instantiation [-fpermissive]
bar(x); // OKAY
^
prog.cpp:10:6: note: ‘template<class T> void bar(T)’ declared here, later in the translation unit
void bar(T x)
^
these requirements may have been changed or clarified in C++11, so it is possible that gcc 4.6's behavior was legal under the C++03 standard.

When the compiler first sees bar(x), it doesn't know x's type, hence it can't look up the correct bar. Only when you instantiate foo, T and therefore x's type are known and bar(x) can be looked up.
Note that this work only for dependent expression, i.e. expressions that depend on a template parameter. If you add bar(42), it will fail to compile even if it is later instantiated with T==int.
You might also want to google "two-phase lookup" for further information. Only recent versions of GCC implement those rules correctly, as some checks also need to be done during the first phase of parsing the template. As pointer out by Yakk, newer versions of GCC reject your code, so always check with up-to-date versions of GCC or Clang to be on the safe side.

A function template isn't a function; it's a recipe for making functions, once the template parameters are known.
The compiler can't look up what bar means when it sees the foo template definition, because what it means could depend on what T is. So it just remembers that there's a use of the name bar that will need to be worked out later.
When you call foo(42) the compile has to produce (instantiate) the real function, and at that point it looks up the names it wasn't able to before, finds your bar template (and triggers instantiation of that too) and all is well.
For a normal function all names can be looked up when the function is defined, and so they must be properly declared at that point.

Related

A template friend function inside a template class

The question of implementing a template friend function inside a template class was already discussed in the past and seem to be an unresolved issue in the standard with different behavior of the different compilers.
Checking newest available versions of gcc and clang it seems that the decision is taken, to require the implementation of template friend function to be outside of the template class.
The following code is rejected by newest versions of both gcc and clang (gcc x86-64 9.2.0 and clang x86-64 9.0.0) when compiled with -std=c++2a. Past versions of clang are ok with it (e.g. clang x86-64 7.0.0).
template<long Num>
struct A {
template<long Num1, long Num2>
friend int foo(A<Num1> a1, A<Num2> a2) {
return 1;
}
// the compilation error occurs only with a template friend function
// and only if *implemented inside* a template class
};
int main() {
A<1> a1;
A<2> a2; // commenting this line removes the error
}
Both compilers complain on redefinition of foo:
<source>:4:16: error: redefinition of 'foo'
friend int foo(A<Num1> a1, A<Num2> a2) {
^
<source>:11:10: note: in instantiation of template class 'A<2>' requested here
A<2> a2;
^
Is there a new official resolution on the subject or is it just the latest compilers fashion?
https://godbolt.org/z/ySrVe3
I figured out the relevant wording from the resolution of CWG 2174. It is in [temp.inst]/2 in C++17:
However, for the purpose of determining whether an instantiated redeclaration is valid according to [basic.def.odr] and [class.mem], a declaration that corresponds to a definition in the template is considered to be a definition.
Thus, the compiler is required to defer the actual instantiation of the definition until the point where a definition of foo is required to exist (in your code, there is no such point, so foo is not instantiated), but even if the definition is not instantiated, the compiler is still required to diagnose multiple definitions within the same translation unit as if the definition had been instantiated every time the declaration were instantiated.
It seems to me that this rule makes it unnecessarily difficult to use friend functions for no obvious benefit, and that it would be better if multiple definitions of a friend function defined inside a class template, instantiated within the same TU, were considered as a single definition. Perhaps, if I had more time on my hands, I would propose making such a change to the standard. (Yes, I am saying I don't have the time, so if anyone else wants to do this, please go ahead without worrying about duplicated effort.)
Unless such a change is made, it seems that you do, in fact, need to define the friend function outside the class template.

Handling gcc's noexcept-type warning

Consider this example, from bug 80985:
template <class Func>
void call(Func f)
{
f();
}
void func() noexcept { }
int main()
{
call(func);
}
Compiling this with all warnings enabled, as you do, yields:
$ g++ -std=c++14 -Wall foo.cxx
foo.cxx:2:6: warning: mangled name for ‘void call(Func) [with Func = void (*)() noexcept]’ will change in C++17 because the exception specification is part of a function type [-Wnoexcept-type]
void call(Func f)
^~~~
What exactly am I supposed to do with this warning? What is the fix?
There's several things you can do about the warning message.
Disable it with -Wno-noexcept-type. In many projects the warning message is unhelpful because there's no chance the resulting object will be linked with an another object that expects it to use GCC's C++17 name mangling. If you're not compiling with different -std= settings and you're not building a static or shared library where the offending function is part of its public interface then the warning message can safely disabled.
Compile all your code with -std=c++17. The warning message will go away as the function will use the new mangled name.
Make the function static. Since the function can no longer be referenced by another object file using a different mangling for the function the warning message will not be displayed. The function definition will have to be included in all compilation units that use it, but for template functions like in your example this is common anyways. Also this won't work for member functions were static means something else.
When calling a function template specify the template parameter explicitly giving a compatible function pointer type that doesn't have the exception specification. For example call<void (*)()>(func). You should also be able to use cast to do this as well, but GCC 7.2.0 still generates a warning even though using -std=c++17 doesn't change the mangling.
When the function isn't a template don't use noexcept with any function pointer types used in the function's type. This and the last point rely on the fact that only non-throwing function pointer types result in naming mangling changes and that non-throwing function pointers can be assigned (C++11) or implicitly converted (C++17) to possibly throwing function pointers.
I'm upvoting Ross's answer for the call<void (*)()>(func) solution. It explicitly tells the compiler that you want the template instantiated for a non-noexcept function type, and guarantees that your code will operate exactly the same in C++17 as it did in C++14.
More alternatives are:
(1) Wrap the noexcept function in a lambda (which isn't noexcept):
template <class Func>
void call(Func f)
{
f();
}
void func() noexcept { }
int main()
{
call([]() { func(); });
}
(2) Create a separate wrapper function without noexcept. This is more typing initially, but if you have multiple call sites it could save typing overall. This is what I ended up doing in the code that originally prompted me to file the GCC bug.
In addition to what is already said, I have found another way to get rid of this warning in GCC 7. Apparently, GCC generates this warning if and only if the first instantiation of call() involves noexcept. So a solution would be first to instantiate call() with a not noexcept function.
This trick would also do:
using dummy = decltype(call(std::declval<void(*)()>()));
P.S. GCC 8.2.1 does not report a warning in this case.
The issue they are warning you about is that in C++14, this will work:
void call(void (*f)())
{
f();
}
void func() noexcept {}
int main(int argc, char* argv[])
{
call(&func);
return 0;
}
but in C++17, you would need to change the declaration of call to be:
void call(void (*f)() noexcept)
{
f();
}
Since you have defined call to be a template, you don't need to worry about this. Still, it could cause you problems because the inferred type is changing, which doesn't usually happen.
For example, this code will compile in C++14 but not C++17:
void foo() noexcept {}
void bar() {}
template <typename F>
void call(bool b, F f1, F f2)
{
if (b)
f1();
else
f2();
}
void foobar(bool b)
{
call(b, &foo, &bar);
}
In C++14, the types of foo and bar are the same, but they are different in C++17, meaning the template resolution will fail. The error message in gcc 7.2 with the flag -std=c++1z is:
note: template argument deduction/substitution failed:
note: deduced conflicting types for parameter 'F' ('void (*)() noexcept' and 'void (*)()')
In the example you've given, there is no issue and you won't have a problem compiling in C++14 or C++17 mode. If the code is more complex than the example here (e.g. similar to the examples I gave above), you could encounter some compiler problems. It seems you have a recent compiler; try compiling with -std=c++1z and see if there are warnings or errors.

What does a compiler check for uninstantiated template code?

For example, the following code piece compiles with gcc-4.9 and clang-602
class Base
{
public:
static void foo() {}
void badfoo(int i) {}
};
template <typename T>
class Derived : public Base
{
public:
void bar() { Base::foo(); }
void badbar() { Base::badfoo(); } // compiles ok
//static void badbar() { Base::badfoo(); } // compile error
//void worsebar() { Base::nonexist(); } // compile error
};
int main()
{
return 0;
}
But the commented out lines won't compile.
My questions are:
Why badbar() compiles but worsebar() doesn't ?
If I change badbar() to static it won't compile either, regardless if base::badfoo is static or not.
Does the standard say anything about what should be checked in this situation ? gcc4.4 actually refuses to compile even badbar().
Update:
Problem 1 has been explained by a number of answers, but it seems compilers sometimes go the extra mile to check overload as well, it happens to gcc 4.4.3 and 4.8.2, but not 4.7.2 and 4.9.1.
Problem 2: As Marco A. pointed out, clang won't compile but gcc4.9 will still pass. However, gcc4.2 and gcc4.4 both reject the code, and the error they are complaining is "no matching function" rather than "calling non-static member without an object" in clang. There's seems to be no conclusive answer to this question, so I'm adding a language-lawyer tag as Daniel Frey suggested.
More Update:
I think for question 2 the answer is pretty clear now: it's up to the compiler whether adding static declaration will change the diagnosis. It varies from compiler to compiler and different versions of the same compiler. The language lawyer didn't show up, I'm going to accept Daniel Frey's answer as it best explained the first question. But answers from Marco A. and Hadi Brais also worth reading.
The standard only requires the name-lookup to happen at phase 1, when the template is first parsed. This turns up badfoo in badbar which is why the code compiles. The compiler is not required to do the overload resolution at that time.
The overload resolution (which always happens as a separate step after the name lookup) is then performed in phase 2 when badbar is instantiated - which is not the case in your example. This principle can be found in
3.4 Name lookup [basic.lookup]
1 The name lookup rules apply uniformly to all names (including typedef-names (7.1.3), namespace-names (7.3), and class-names (9.1)) wherever the grammar allows such names in the context discussed by a particular rule. Name lookup associates the use of a name with a declaration (3.1) of that name. Name lookup shall find an unambiguous declaration for the name (see 10.2). Name lookup may associate more than one declaration with a name if it finds the name to be a function name; the declarations are said to form a set of overloaded functions (13.1). Overload resolution (13.3) takes place after name lookup has succeeded. The access rules (Clause 11) are considered only once name lookup and function overload resolution (if applicable) have succeeded. Only after name lookup, function overload resolution (if applicable) and access checking have succeeded are the attributes introduced by the name’s declaration used further in expression processing (Clause 5).
(Emphasis mine)
I'd therefore say that the compiler(s) are correct to accept the code, although I'm not sure that they are required to do so.
To see the code being rejected, you need instantiate badbar.
Consider [temp.res]/8:
If no valid specialization can be generated for a template, and that
template is not instantiated, the template is ill-formed, no
diagnostic required.
This (in particular the "no diagnostic required" bit) makes any compiler's behaviour compliant with respect to worsebar. Implementations' discrepancies on this kind of code are just QoI issues - common compilers do some analysis and will complain. It is hard to say when exactly, and you should be prepared to come back to template code when upgrading or switching your implementation.
To make some clarity.. this version of the code compiles just fine on clang and gcc
class Base
{
public:
static void foo() {}
void badfoo(int a) {}
};
template <typename T>
class Derived : public Base
{
public:
void bar() { Base::foo(); }
void badbar() { Base::badfoo(); }
};
since
[temp.res]/p8
If no valid specialization can
be generated for a template, and that template is not instantiated, the template is ill-formed, no diagnostic
required.
Both gcc and clang aren't required to diagnose this. This one also falls in the same case as above (clang emits an error, gcc doesn't)
class Base
{
public:
static void foo() {}
void badfoo(int a) {}
};
template <typename T>
class Derived : public Base
{
public:
void bar() { Base::foo(); }
static void badbar() { Base::badfoo(); }
};
The case with
void worsebar() { Base::nonexist(); }
is different since it violates name lookup [temp.res]/p9
When looking for the declaration of a name used in a template definition, the usual lookup rules (3.4.1,
3.4.2) are used for non-dependent names
and [temp.res]/p10
If a name does not depend on a template-parameter (as defined in 14.6.2), a declaration (or set of declarations)
for that name shall be in scope at the point where the name appears in the template definition
Disclaimer: all of the above does not apply to MSVC which happily postpones all this stuff to the second phase of the lookup.
Edit:
in the case
class Base
{
public:
static void foo() {}
void badfoo(int i) {}
};
template <typename T>
class Derived : public Base
{
public:
static void badbar() { Base::badfoo(); } // static function
clang triggers an error while gcc doesn't. This falls in the first case since name lookup is successful but clang performs an additional check: since badfoo is a member function it tries to construct a valid implicit member reference expression. It then catches the fact that a member function is implicitly being called from a static function and detects the context mismatch. This diagnostic is entirely up to the compiler at this point (it wouldn't in case of an instantiation).
Before it instantiates any types or emits any code, the compiler incrementally builds a table of all symbols that have been declared. If an undeclared symbol has been used, it emits an error. That's why worsebar won't compile. On the other hand, badfoo has been declared and so badbar compiles. At this early point in the compilation process, the compiler won't check whether the call to badfoo actually matches the declared badfoo.
Since the Derived type has not been instantiated anywhere in the code, the compiler will not emit any code regarding it. In particular, badbar will just be neglected.
Now when you declare an instance of Derived (such as Derived< int >) but without using any of its members, the compiler will just create a type with those members that have been used and omit the others. Still, no error regarding badbar.
However, when declaring an instance of Derived and calling badbar, an instantiation of the badbar method would be required and so the compiler will create a type with badbar and compile it. This time, the compiler notices that badfoo is not actually declared and therefore emits an error.
This behavior is documented in the C++ standard in section 14.7.1.
Unless a member of a class template or a member template has been explicitly instantiated or explicitly specialized, the specialization of the member is implicitly instantiated when the specialization is referenced in a context that requires the member definition to exist.
Finally, if badbar was static and was instantiated by the compiler (because it has been used) then the compiler will emit an error that badfoo does not exist. Now if you pass an integer argument to badfoo, another error will be emitted indicating that a static method cannot access an instance member because there is no instance in the first place.
Edit
The compiler is not obliged to NOT report semantic errors in uninstantiated template types. The standard just says that it does not have to, but it can. Regarding where to draw the line is open for debate. See this discussion about a related issue in clang:
which uninstantiated templates do we analyze? For performance reasons, I don't think we should analyze all the uninstantiated templates, as we may find ourselves repeatedly analyzing a huge portion of the Boost and the STL, etc.
So uninstantiated templates analysis changes with different versions of clang and gcc in different ways. But again, as per the standard: There's no requirement to report errors in uninstantiated templates, of course.
At first if you would instantiate Devired and try to call badbar there would be a compilation error:
// ...
int main()
{
Derived<int> d;
d.badbar();
return 0;
}
produces
error: too few arguments to function call, single argument 'i' was not specified
void badbar() { Base::badfoo(); } // compiles ok
~~~~~~~~~~~~ ^
The compiler doesn't compile the code, that is not instantiated.

A C++ template is just "grammar safe" and not type safe first?

C++ templates are checked at least twice. First, when a template is declared & defined, second when it is instantiated. After a template successfully instantiated it is in a type safe state. My question is that what is the name of the state where a template is in when a template is successfully declared & defined?
If I compare macro with templates, is it true that after a successful macro "instantiation" the code is type safe?
#define BAR(x) return x;
^
// BAR is preprocessor-grammar-safe here?
struct Bar
{
static void bar() {}
};
^
// Bar is type safe at this point?
template<typename T>
void foo()
{
T::bar();
}
^
// foo is C++-grammar safe at this point?
int main()
{
foo<Bar>();
^
// foo is type safe at this point?
foo<int>();
^
// foo is ill-formed here?
BAR(0);
^
// BAR is type safe at this point?
return 0;
}
Think of a C++ template as a macro on steroids and having syntactical knowledge.
ex.
template<typename T>
void func(T t) {
t.foo();
...
Nothing declares the fact that T must have a foo() function;
This distinguishes C++ templates from things like Scala type parameters.
I believe newer C++ versions have added some support for this. You basically let the compile "try" using the t.foo() and if there's no such function it fails to compile.
A template is a template.
A type is a type.
Types may be obtained by specializing templates ("instantiating" in colloquial speech).
Templates and types have names. Types that are unions and classes must be declared, and defined in order to be complete. Templates must be declared, and defined in order to specialized.
That's all I can think of, and that should be enough vocabulary to talk about most aspects of the type system of C++ on a "first draft" kind of level.
You just miss a little point: Macro processing is text processing (done before compilation)
Assuming preprocessing has generated valid code:
A template can be successfully declared. Instantiation (definition) might fail, however.
Essentially BAR(0); is not type safe (exaggerating a bit here) !

Name resolution in templates

I was reading about the template name resolution here. Just to get the feel of the things I replicated the code like this:
void f (char c)
{
std::cout<<"f(char)\n";
}
template <class T>
void g(T t)
{
f(1);
f(T(1));
f(t);
d++;
}
double d;
void f(int n)
{
std::cout<<"f(int)\n";
}
void test()
{
std::cout<<"First call\n";
g(1);
std::cout<<"Second call\n";
g('a');
}
int main()
{
test();
return 0;
}
According to the article linked I should have a compiler error for the d++ statement. Also for the first call of g(1), I should have one call of f(char) followed by two calls of f(int) and for the second call I should get three calls of f(char). However, when I compiled this using Vs2008, it compiled fine without any errors. Also, the output was:
First call
f(int)
f(int)
f(int)
Second call
f(int)
f(char)
f(char)
I am now wondering which one is correct? The article I am linking to or the VS2008 output? Any clue which is correct?
Also for the first call of g(1), I should have one call of f(char) followed by two calls of f(int) and for the second call I should get three calls of f(char).
This is not the expected result with a Standard compliant compiler. Since both time you call it with a fundamental type, you will not get name lookup at the instantiation context for the function call.
Name lookup at instantiation context only happens for argument dependent lookup (called lookup using associated namespaces). Both of int and char do not have argument dependent lookup, an thus all the function calls you do will call f(char) after you removed the d++ line.
Since i understand you won't possibly just believe me, here is the Standard quote, out of 14.6.4.2:
For a function call that depends on a template parameter, if the function name is an unqualified-id but not a template-id, the candidate functions are found using the usual lookup rules (3.4.1, 3.4.2) except that:
For the part of the lookup using unqualified name lookup (3.4.1), only function declarations with external linkage from the template definition context are found.
For the part of the lookup using associated namespaces (3.4.2), only function declarations with external linkage found in either the template definition context or the template instantiation context are found.
Note that the article uses a defective example of the Standard (at 14.6/9) (and note that examples are non-normative: They can't change or state rules. Their purpose entirely is illustrative). The defect has been fixed and is incorporated into the upcoming Standard. See this defect report.
As you see, you will have to change from int / char to some user defined type (enums or classes) too see the effect of lookup in instantiation context. Read this answer Order affects visibility for more information.
Even though VS2008 was considered the most standard-compliant C++ compiler of it's time, here we have one instance where it's accepting invalid code. G++ doesn't compile this (d++: error: 'd' was not declared in this scope). That said, any program that relies this much on the intricacies of the C++ language is broken anyway :)
The article is correct about whether d++ should compile.
Visual C++ does not do two-phase template instantiation - it does pretty much all its parsing at instatiation time.
Gcc and Comeau will give the correct error and will call the correct f.
VS should have complained about d++ as d should be looked up at point of definition.
The article is incorrect, the calls should be resolved to f(char) as point of instantiation lookup should not be done for fundamental types (see tlib answer).
g++ behaviour depends on the version:
before 3.4, it does always point of instantiation lookup, which is a bug.
starting with 3.4, it does point of definition lookup for d; but it does point of
instantiation lookup for fundamental types when they are a template parameter, which
is a bug.
starting with 4.1, it doesn't do point of instantiation lookup for basic types anymore.