我试图为this question创建我的代码的简化版本。在这个过程中,我遇到了一些对我没有意义的事情。有人可以解释为什么我得到以下结果?这是代码,它应该在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;
}
这是输出:
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.
首先,它使用字符串版本调用writeData
。在我尝试使用binaryWrite
函数write
(此函数调用writeData
)调用该版本后,它会调用模板定义的函数。
我玩了它并发现如果我将字符串的重载函数移到binaryWrite
的类定义之上,那么我得到了我想要的结果。
这是改变:
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);
}
};
这是输出
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
在第一种情况下,似乎binaryWrite
不知道writeData
的重载函数string
。但是在切换之后,由于我首先定义了重载函数,所以它知道了。这是正确的解释吗?
我最想做的是将宏WRITESTRUCT
用于其他类型,但这个定义会出现在其他一些文件中,所以在binaryWrite
的定义之前我将无法编写它们。如果我的解释确实是正确的,那么如何克服这个问题?
答案 0 :(得分:2)
好的,使用您的代码,我发现如果您移动所有writeData
模板并在binaryWrite
类定义下方重载,它也能正常执行。
当编译器遇到binaryWrite::write
时,它会检查该点是否有writeData
的定义。此时它正在选择template <typename T> inline void writeData(const T& x)
,因为它只能访问前两个模板。然后再回过头来看看是否有更好的选择。
在binaryWrite之后移动writeData模板时,编译器没有writeData的定义,并决定在模板实例化期间它会再次查找。因此,当您使用binaryWrite::write
时,它会选择直接重载,而不是模板。
答案 1 :(得分:1)
您的三个职能是:
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);
我不知道为什么template<typename T> void write(const T& x, const char* name)
决定第三个选项不够好,但是如果你将第三个选项变成writeData
的模板特化而不是问题就会消失过载:
template <> inline void writeData<string>(const string& s);
另外,摆脱那些宏。我没有看到WRITESTRUCT(string, s)
如何比void writeData(const std::string& s)
更清晰,特别是因为没有涉及结构。
答案 2 :(得分:1)
是的,正确的解决方案是移动重载函数,或者至少移动它的声明,以便它对binaryWrite可见。
有些编译器没有正确地执行此操作并且包含在binaryWrite之后声明的函数,但在使用之前,在所考虑的重载集中。如果可见函数集在不同的地方不相同,这可能会导致有趣的ODR违规。