问题是,为什么只有对M::operator<<
的调用会导致链接错误,而不是调用std::cout::operator<<
时会出现错误?
代码如下:
#include <iostream>
struct M {
inline M() {}
template <typename T>
inline M& operator <<(const T& val) {
std::cout << "ref." << val;
return *this;
}
template <typename T>
inline M& operator <<(T* const& pointer) { // NOLINT
std::cout << "ptr." << pointer;
return *this;
}
};
class PJTest
{
public:
~PJTest()
{
M()
<< "Failed to remove file '" << fname << "' because: stuff\n"; // 25
std::cout
<< "Failed to remove file '" << fname << "' because: stuff\n"; // 28
}
protected:
static auto constexpr fname = "what's in a name?";
};
int main() {
PJTest pt;
}
使用g++ -g -O0 -std=c++11 -Wall -pedantic -Wextra wtf.cc
进行编译会导致
wtf_test.cc:25: undefined reference to `PJTest::fname'
请注意第28行没有错误!
g++ -g -O2 -std=c++11 -Wall -pedantic -Wextra wtf.cc
成功。
(g ++ 4.8.4来自Ubuntu 14.04LTS),行为与G ++ 5.3.0相同
无论优化级别如何,使用clang ++进行编译总是会失败,但同样只适用于第25行;我知道我可以通过添加constexpr const char* PJTest::fname;
来解决此问题,但我想了解为什么它会在clang ++中导致错误。
答案 0 :(得分:4)
答案是 - 因为std::ostream
已选择const char*
的非模板版本:
在你的程序中也有这样的版本:
inline M& operator <<(const char* val) {
std::cout << "str." << val;
return *this;
}
你的代码编译没有问题。
更多背景 - 您的真实fname
类型为char[18]
- 所以编译器最佳猜测是:
template <typename T>
inline M& operator <<(const T& val) {
std::cout << "ref." << val;
return *this;
}
正如您所看到的 - 此版本需要引用 - 或多或少这意味着fname
应该有一个地址 - 它不能是真正优化的const。
您也可以通过定义它来为此变量赋予地址 - 就像类的任何其他静态变量一样:
class PJTest
{
//....
protected:
static auto constexpr fname = "what's in a name?";
};
decltype(PJTest::fname) constexpr PJTest::fname;
重载过载非常困难 - 大多数细节都是here,模板作为新的并发症级别 - 阅读here。
只是为了让事情变得更简单 - 让我们调查更简单的形式:
f(int const&)
- 它需要&#34;地址&#34; 代码:
class PJTest
{
public:
static auto constexpr fvalue = 113;
};
//decltype(PJTest::fname) constexpr PJTest::fname;
void f(const int&) {}
void f(double) {}
int main() {
f(PJTest::fvalue);
}
const int
转换为const double
- 不是&#34;地址&#34;需要:代码:
class PJTest
{
public:
static auto constexpr fvalue = 113;
};
//decltype(PJTest::fname) constexpr PJTest::fname;
void f(double) {}
int main() {
f(PJTest::fvalue);
}
代码:
class PJTest
{
public:
static auto constexpr fvalue = 113;
};
//decltype(PJTest::fname) constexpr PJTest::fname;
template <typaname T>
void f(const T&) {}
void f(double) {}
int main() {
f(PJTest::fvalue);
}
代码:
class PJTest
{
public:
static auto constexpr fvalue = 113;
};
//decltype(PJTest::fname) constexpr PJTest::fname;
template <typaname T>
void f(const T&) {}
int main() {
f(PJTest::fvalue);
}