Consider the following code, taken from https://www.ibm.com/support/knowledgecenter/en/SSLTBW_2.3.0/com.ibm.zos.v2r3.cbclx01/name_binding.htm:
#include <iostream>
using namespace std;
void f(double) { cout << "Function f(double)" << endl; }
template <class A> struct container{ // point of definition of container
void member1(){
// This call is not template dependent,
// because it does not make any use of a template parameter.
// The name is resolved at the point of definition, so f(int) is not visible.
f(1);
}
void member2(A arg);
};
void f(int) { cout << "Function f(int)" << endl; }
void h(double) { cout << "Function h(double)" << endl; }
template <class A> void container<A>::member2(A arg){
// This call is template dependent, so qualified name lookup only finds
// names visible at the point of instantiation.
::h(arg);
}
template struct container<int>; // point of instantiation of container<int>
void h(int) { cout << "Function h(int)" << endl; }
int main(void){
container<int> test;
test.member1();
test.member2(10);
return 0;
}
The output is
Function f(double)
Function h(double)
I understand this, but what I don't understand, when the article states
The point of instantiation of a template is located immediately before
the declaration that encloses its use. In this example, the point of
instantiation of container is the location of the explicit
instantiation
...is why when I move the definition of void h(int) above what is labelled as the point of instantiation, h(int) still does not get called. It only gets called when I move it above the definition of the function void container<A>::member2(A).
This is the case in VS2017 and g++, so clearly either the article is badly worded or I am missing something. Can someone please clarify?
OK, the link posted above (point of instantiation and name binding) ultimately does answer this question, however it is not as clear as it could be. I have found this page and this page which further aided in my understanding, hence I post them here so others can benefit.
Related
Is it possible to recognize all calling of a certain function in everywhere
function1<T1>(); function1<T4>(); ...
then add a line that calling this following line in a certain place?
function2<T1>(); function2<T4>(); ...
For example,
class X{
template <class T> function1(){ }
template <class T> function2(){ }
}
class A{}
class B{}
class C{}
int main(){
X x;
//vvvv this code (hopefully) will be auto generated (by macro?)
x.function2<A>();
x.function2<B>(); //<--- I don't care about order of A or B
//x.function2<C>(); //<--- this line should not be generated
//^^^^ Only X's function1 should be recognized,
// not other class's functions with the same name.
x.function1<B>();
x.function1<A>();
x.function1<B>(); .... // called in various places in many .cpp
//If it is called in another .cpp, but not here, it should still be recognized
}
Edit
My old code call :-
function2<T>() inside function1<T>()
It costs CPU significantly (I profiled), because function1 have to check whether function2 was called or not every time.
Here is a draft of a near-zero overhead solution that will work only if you are not going to invoke function1() before main():
#include <iostream>
#include <typeinfo>
template <class T>
void function2()
{
std::cout << "function2<" << typeid(T).name() << ">()" << std::endl;
}
bool dummy = true;
template <class T>
struct Func1WasInstantiated
{
struct CallFunc2
{
CallFunc2() { function2<T>(); }
void operator()() const { dummy = false; }
};
static CallFunc2 callFunc2;
};
template <class T>
typename Func1WasInstantiated<T>::CallFunc2 Func1WasInstantiated<T>::callFunc2;
template <class T>
void function1()
{
Func1WasInstantiated<T>::callFunc2();
std::cout << "function1<" << typeid(T).name() << ">()" << std::endl;
}
int main()
{
std::cout << "------- Entered main() ---------" << std::endl;
function1<int>();
function1<double>();
function1<int>();
return 0;
}
Output (check it on IDEONE):
function2<i>()
function2<d>()
------- Entered main() ---------
function1<i>()
function1<d>()
function1<i>()
The global variable dummy is the acceptor of the side effect, that ensures that Func1WasInstantiated<T>::callFunc2 is linked into the program and makes the code work as intended. Without the side effect contained in callFunc2() I can imagine an aggressively optimizing compiler eliminating that line from function1() (that is normal) and letting the linker leave out the callFunc2 objects as they become unreferenced (I cannot judge whether this would be against the C++ standard or not).
I have a template class, and I define a friend function inside the class.
#include <iostream>
using namespace std;
template <typename T>
class template_class {
T v;
friend void foo(template_class t) {
t.v = 1; // (1)can access the private member because it's a friend
cout << t.v << endl;
template_class<int> t1;
t1.v = 2; // (2)accessible if instantiated with [T=int]
cout << t1.v << endl;
template_class<char> t2;
t2.v = 'c'; // (3)should not be accessible too if instantiated with [T=int]
cout << t2.v << endl;
}
};
int main() {
template_class<int> t; // (4)generate void foo(template_class<int> t)
foo(t);
return 0;
}
If my understanding is correct, (4) generate the function void foo(template_class<int>), and make it the friend of template_class<int>, so it can access the private member of template_class<int> like (1) and (2) in above source. But (3) should not be OK too, it's not the friend of template_class<char>, only void foo(template_class<char>) will be the friend of template_class<char>.
EDIT
As #Constructor and #Chnossos said, The above source compiled OK with gcc 4.8.1, but failed with clang 3.4. So which one is correct? Is it just a bug of gcc? Does the standard has an explicit definition about this case?
As dyp says in the comments, this is simply a GCC bug. Either PR 41437 or one of the others that PR 59002 links to.
I have an object like the following
template<typename T>
inline void UnusedParameter( T const& )
{
}
class Client
{
public:
template<class T>
void runFFT(T *wSamples, float const &fMult)
{
std::cout << "INSIDE RUNFFT : : :" << std::endl;
UnusedParameter(wSamples);
UnusedParameter(fMult);
}
};
And in my CPP I have the following:
#include "object.hpp"
template<>
void Client::runFFT<int16_t>(int16_t *wSamples, float const &fMult)
{
std::cout << "INSIDE INT16_T version: : :" << std::endl;
UnusedParameter(wSamples);
UnusedParameter(fMult);
}
template<>
void Client::runFFT<Ipp32f>(Ipp32f *wSamples, float const &fMult)
{
std::cout << "INSIDE IPP32F version: : :" << std::endl;
UnusedParameter(wSamples);
UnusedParameter(fMult);
}
Both these implementation run without any problem in my Debug Code. It enters the int16_t version without problem and the Ipp32f version also without problem.
But when I try the Run version it only enters the Template, like the compiler only compiles the Template implementation in the header.
How do I prevent this from happenning? Shall I remove this and just create two different methods? I love my templates but these Heisenberg bugs are frustating.
Thanks for any input.
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
Andy Prowl answered this question and it is solved doing the following in the HPP:
template<typename T>
inline void UnusedParameter( T const& )
{
}
class Client
{
public:
template<class T>
void runFFT(T *, float const &)
{
// Thanks for Joachim for removing my Unused Parameter crap
std::cout << "INSIDE RUNFFT : : :" << std::endl;
}
};
template<>
void Client::runFFT<int16_t>(int16_t *wSamples, float const &fMult);
template<>
void Client::runFFT<Ipp32f>(Ipp32f *wSamples, float const &fMult);
And now it works in runtime as well. The CPP stays the same.
The problem is most likely in the fact that you relegated the specializations of your member function runFFT() for int16_t and Ipp32f in a separate .cpp file without providing a corresponding declaration after the primary template, so the compiler at the point of instantiation (which likely belongs to another translation unit that #includes only the header file containing the definition of Client) doesn't know about the existence of those explicit specializations.
Put a declaration for those specializations in the same header file that contains the definition of your class template:
template<typename T>
inline void UnusedParameter( T const& ) { }
class Client
{
public:
template<class T>
void runFFT(T *wSamples, float const &fMult)
{
std::cout << "INSIDE RUNFFT : : :" << std::endl;
UnusedParameter(wSamples);
UnusedParameter(fMult);
}
};
// DECLARE YOUR EXPLICIT SPECIALIZATIONS HERE
template<>
void Client::runFFT<int16_t>(int16_t *wSamples, float const &fMult);
template<>
void Client::runFFT<Ipp32f>(Ipp32f *wSamples, float const &fMult);
Per Paragraph 14.7.3/6 of the C++11 Standard:
If a template, a member template or a member of a class template is explicitly specialized then that specialization
shall be declared before the first use of that specialization that would cause an implicit instantiation
to take place, in every translation unit in which such a use occurs; no diagnostic is required. [...]
The "no diagnostic is required" part means that if you don't follow this rule, your program will be ill-formed, but your compiler/linker is not required to tell you. This normally results in the kind of undefined behavior you are observing.
This is kind of a follow on to this question.
#include <iostream>
struct type1 {};
struct type2 {};
void foo(type1 x)
{
std::cout << "foo(type1)" << std::endl;
}
template<typename T>
void bar() {
foo(T());
}
int main()
{
bar<type1>();
bar<type2>();
return 0;
}
void foo(type2 x)
{
std::cout << "foo(type2)" << std::endl;
}
In the above code foo(type2) is not visible at the time of instantiation of bar<type2> in main. And yet the code compiles and produces the following output :
foo(type1)
foo(type2)
How does the compiler know that foo(type2) is available when instantiating bar<type2> in main?
EDIT : I am trying to understand more about how overload resolution during template instantiation works. Consider the code below :
#include <iostream>
struct type1 {};
struct type2 {};
struct type3 {
operator type2() { return type2(); }
};
void foo(type1 x)
{
std::cout << "foo(type1)" << std::endl;
}
void foo(type2 x)
{
std::cout << "foo(type2)" << std::endl;
}
int main()
{
foo(type3());
return 0;
}
void foo(type3 x)
{
std::cout << "foo(type3)" << std::endl;
}
The output is
foo(type2)
Even though a closer match foo(type3) is available, the call foo(type3()) resolves to foo(type2) because that was the only candidate that has been parsed by the compiler until that point. Now consider the following code :
#include <iostream>
struct type1 {};
struct type2 {};
struct type3 {
operator type2() { return type2(); }
};
void foo(type2 x)
{
std::cout << "foo(type2)" << std::endl;
}
template<typename T>
void bar() {
foo(T());
}
int main()
{
bar<type3>();
return 0;
}
void foo(type3 x)
{
std::cout << "foo(type3)" << std::endl;
}
The output is
foo(type3)
That is, at the point of the call bar<type3>(), even though only foo(type2) is visible, the compiler still picks foo(type3) that comes later because that is a closer match.
Any symbol left without a definition is to be replaced during the linking process, since the function foo(type2) could've been provided in another file.
The compiler is to say whether the function needed has been defined by the end of the entire process, when no further substitution can be applied.
In order to clarify the understanding, you must be aware of the steps required to compile, say, a common C program:
first, you expand all the macros on your code;
then your code is validated according to the language syntax, so that it can be converted into assembly language -- the compilation process itself; during this step, every symbol found without a definition is annotated in a table with the entries (symbol, definition), that shall be completed later, allowing your program to be constructed properly;
next, your code compiled into assembly will be converted to machine language, i.e., the objects will be created;
finally, you need to link your already executable objects, in order to solve any dependencies on symbol definitions; this last step checks your objects for undefined symbols, adding definitions from other modules or from libraries, thus, completing the program.
If any symbol was not correctly "linked" to its definition, the compiler will point out an error in your program -- the classic undefined reference to....
Considering the code you've posted, the process would be executed until it reaches the compiler. The compiler would traverse the code, notice the definition of type1, type2, foo(type1 x), and bar<T>().
struct type1 {};
struct type2 {};
When it'd reached the main, it would find the call for bar<type1>();, and would call foo(type1()), which is already known, and can be used properly.
void foo(type1 x) {
std::cout << "foo(type1)" << std::endl;
}
template<typename T>
void bar() {
foo(T());
}
int main() {
bar<type1>();
bar<type2>();
return 0;
}
Once it'd reached the next call, bar<type2>();, it would try to call foo(type2()), but no such definition would be available for usage, so it would relate this call as an unknown symbol, that must be replaced by a definition in the later processes.
After the compiler runs through the main, it reaches a new definition, that is exactly the one lacking definition on the "translation table" being created.
void foo(type2 x) {
std::cout << "foo(type2)" << std::endl;
}
So, in the next step, the compilation is able to replace the symbol with its respective definition, and the program compiles correctly.
Regards!
The answer is found via argument-dependent name lookup (ADL) (which is also mentioned in the linked question). foo(T()); has two lookups. First at template definition time, any functions defined at the point of definition are included in the overload set. This means when the compiler sees foo(T()); inside of bar, it adds only void foo(type1 x) to the overload set. However there is a second lookup that is performed, called ADL. At template instantiation time, i.e. bar<type2>(); it looks for a foo in the same namespace as the argument which is provided, which in this case is type2. Since type2 is in the global namespace, it looks for a foo that takes a type2 in the global namespace and finds it, and resolves the call. If you are looking for info from the standard, see 14.6.4.2 Candidate functions.
Try the following and watch the code fail. This is because it cannot find foo in the same namespace as a::type1.
#include <iostream>
namespace a
{
struct type1 {};
}
template<typename T>
void bar() {
foo(T());
}
int main()
{
bar<a::type1>();
return 0;
}
void foo(a::type1 x)
{
std::cout << "foo(a::type1)" << std::endl;
}
When I try to specialize a public member function template within the class definition/declaration:
#include <iostream>
class surfaceMesh
{
public:
// Uncomment for Version 0 and 1
class AREA_AVERAGE {};
class ANGLE_AVERAGE {};
template<class Average>
void vertexNormals() {}
// Uncomment: Version 0
//template<>
//void vertexNormals<AREA_AVERAGE> ()
//{
//std::cout << "AREA_AVERAGE" << std::endl;
//}
//template<>
//void vertexNormals<ANGLE_AVERAGE> ()
//{
//std::cout << "ANGLE_AVERAGE" << std::endl;
//}
};
// Uncommend for version 1
template<>
void surfaceMesh::vertexNormals<surfaceMesh::AREA_AVERAGE> ()
{
std::cout << "AREA_AVERAGE" << std::endl;
};
template<>
void surfaceMesh::vertexNormals<surfaceMesh::ANGLE_AVERAGE> ()
{
std::cout << "ANGLE_AVERAGE" << std::endl;
};
int main()
{
surfaceMesh m;
m.vertexNormals<surfaceMesh::AREA_AVERAGE>();
m.vertexNormals<surfaceMesh::ANGLE_AVERAGE>();
return 0;
}
For Version 0, the error is:
main.cpp:19: error: template-id ‘vertexNormals<mesh::AREA_AVERAGE>’ in declaration of primary template
main.cpp:24: error: explicit specialization in non-namespace scope ‘class mesh’
main.cpp:25: error: template-id ‘vertexNormals<mesh::ANGLE_AVERAGE>’ in declaration of primary template
main.cpp:25: error: ‘void mesh::vertexNormals()’ cannot be overloaded
main.cpp:19: error: with ‘void mesh::vertexNormals()’
Version 1 compiles and runs. Of course, usually I am separating the class declaration and definition, but I would really like to know why this happens.
Also, is this a good way to specialize an interface? The other option would be to overload the function vertexNormals to take an object of AREA_AVERAGE or ANGLE_AVERAGE, but this is just a type telling me which kind of function I will be using, it is not supposed to be instantiated, so using templates 'feels' like a right choice.
Why is it not allowed to specialize a member function template within a class?
Because that is the rule laid down by the C++ Standard.
As for what you want, a better approach is to use function overload rather than function specialization as:
class surfaceMesh
{
public:
// Uncomment for Version 0 and 1
class AREA_AVERAGE {};
class ANGLE_AVERAGE {};
template<class Average>
void vertexNormals()
{
//invoke the function overload
vertexNormals(static_cast<Average*>(0));
}
private:
//make the overloads private, so client will not call them!
void vertexNormals(AREA_AVERAGE *)
{
std::cout << "AREA_AVERAGE" << std::endl;
}
void vertexNormals(ANGLE_AVERAGE*)
{
std::cout << "ANGLE_AVERAGE " << std::endl;
}
};
The type of the expression static_cast<Average*>(0) helps the compiler to choose the correct overload.