I was trying to make a simplified version of my code for this question. In the process I encountered something that does not make sense to me. Can someone explain why I obtain the following result? Here is the code, it should compile and run in gcc.
#include <string>
#include <iostream>
#include <typeinfo>
using std::string;
template <typename T> inline char getType(const T&) {return 'S'; }
inline char getType(const char&) {return 'C';}
template <typename T> inline char getType(T*) {return 'A'; }
template <typename T> inline void writeData(const T& x) {
printf("Calling default writeData...\n");
char type = getType(x);
if (type == 'S') {
printf("ERROR: binaryWrite::writeData -> Structure not defined.\n");
exit(1);
}
std::cout << x << std::endl;
}
template <typename T> inline void writeData(T* x, const unsigned int& len) {
printf("Writing array with writeData...\n");
char type = getType(x[0]);
std::cout << len << std::endl;
if (type == 'S') {
for (int i=0; i < len; ++i) {
writeData(x[i]);
}
} else {
for (int i=0; i < len; ++i) {
std::cout << x[i] << std::endl;
}
}
}
class binaryWrite {
public:
binaryWrite(void) {}
template <typename T>
void write(const T& x, const char* name) {
writeData(x);
}
};
inline void writeData(const string& s) {
unsigned int len = s.size();
const char* pt = s.c_str();
writeData(pt, len);
}
int main () {
string str = "Hello World";
writeData(str);
binaryWrite BF;
BF.write(str, "str");
return 0;
}
This is the output:
manuel-lopezs-macbook-pro:binaryFiles jmlopez$ g++ -o example example.cpp
manuel-lopezs-macbook-pro:binaryFiles jmlopez$ ./example
Writing array with writeData...
11
H
e
l
l
o
W
o
r
l
d
Calling default writeData...
ERROR: binaryWrite::writeData -> Structure not defined.
First it calls writeData
with the string version. After I try calling that version with the binaryWrite
function write
(This function calls writeData
) it calls the function defined by the template.
I played around with it and found out that if I move the overloaded function for the string right above the class definition of binaryWrite
then I get the result that I want.
This is the change:开发者_JAVA百科
inline void writeData(const string& s) {
unsigned int len = s.size();
const char* pt = s.c_str();
writeData(pt, len);
}
class binaryWrite {
public:
binaryWrite(void) {}
template <typename T>
void write(const T& x, const char* name) {
writeData(x);
}
};
This is the output
Writing array with writeData...
11
H
e
l
l
o
W
o
r
l
d
Writing array with writeData...
11
H
e
l
l
o
W
o
r
l
d
It would seem as if binaryWrite
did not know about the overloaded function writeData
for string
in the first case. But after the switch, since I defined the overloaded function first then it knows. Is this the right explanation?
What I would like to do eventually is use the macro WRITESTRUCT
for other types but this definition would be in some other files so I won't be able to write them before the definition of binaryWrite
. Any ideas how to overcome this problem if my explanation is indeed the right one?
Okay, playing around with your code, I found it also performs correctly if you move ALL of the writeData
templates and overload below the binaryWrite
class definition.
When the compiler encounters binaryWrite::write
, it checks to see if it has a definition for writeData
at that point. It's selecting template <typename T> inline void writeData(const T& x)
at that point because it only has access to the first two templates. It then never goes back to see if there is a better choice.
When you move the writeData templates after binaryWrite, the compiler has no definition for writeData, and decides it will look again during template instantiation. So when you then use binaryWrite::write
, it picks the direct overload, instead of the template.
Your three functions are:
template <typename T> inline void writeData(const T& x);
template <typename T> inline void writeData(T* x, CIX len);
inline void writeData(const string& s);
I haven't any idea why template<typename T> void write(const T& x, const char* name)
decided that the third option wasn't good enough, but the problem goes away if you make that third one into a template specialization of writeData
, instead of an overload:
template <> inline void writeData<string>(const string& s);
Also, get rid of those macros. I don't see how WRITESTRUCT(string, s)
is clearer than void writeData(const std::string& s)
, especially since there's no struct involved.
Yes, the correct solution is to move the overloaded function, or at least its declaration, so that it is visible to binaryWrite.
Some compilers don't do this properly and include functions declared after binaryWrite, but before its use, in the set of overloads considered. This can lead to interesting ODR violations, if the set of visible functions are not the same in different places.
精彩评论