以下是一些代码:
#include<iostream>
using namespace std;
class ShowHello {
public:
string operator()(int x) {return "hello";}
};
template<typename F>
class A {
private:
static F f;
static inline string foo(const int& x) {
return f(x);
}
public:
A() {
cout << "foo: " << foo(10) << endl;
}
};
int main(int argc, char *argv[])
{
A<ShowHello> a;
return 0;
}
这是我通过一些优化来编译它:
$ g++ -std=c++11 -O1 -Wall test.cc -o test && ./test
foo: hello
没有优化
$ g++ -std=c++11 -O0 -Wall test.cc -o test && ./test
/tmp/ccXdtXVe.o: In function `A<ShowHello>::foo(int const&)':
test.cc:(.text._ZN1AI9ShowHelloE3fooERKi[_ZN1AI9ShowHelloE3fooERKi]+0x2a): undefined reference to `A<ShowHello>::f'
collect2: error: ld returned 1 exit status
我做错了什么?
另外
$ g++ --version
g++ (Ubuntu 5.4.0-6ubuntu1~16.04.5) 5.4.0 20160609
Copyright (C) 2015 Free Software Foundation, Inc.
This is free software; see the source for copying conditions. There is NO
warranty; not even for MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
答案 0 :(得分:5)
你在这里声明一个静态成员变量f
:
static F f;
然后你odr-use在这里:
static inline string foo(const int& x) {
return f(x);
}
这需要f
的定义可用,但您还没有提供定义 - 只是声明。这使得该计划形成不良,无需诊断。但是,实际上,只有链接器实际需要它时才需要定义 - 在这种情况下,优化的构建只是完全内联调用,甚至不用打扰静态成员或类。实际上,指示包括有趣的事情:
movl $1819043176, 16(%rsp) // this is "hell"
movl $5, %edx
movl std::cout, %edi
movq $5, 8(%rsp)
movb $111, 4(%rsi) // this is 'o'
很酷的东西。
无论如何,未经优化的构建实际上依赖于f
的定义,因为调用实际上是 - 并且您没有定义,因此链接器错误。优化后的构建并不依赖f
,但无论如何都应该定义它,以确保正确性。
template <typename F>
struct A { ... };
template <typename F>
F A<F>::f;