Welcome to OGeek Q&A Community for programmer and developer-Open, Learning and Share
Welcome To Ask or Share your Answers For Others

Categories

0 votes
231 views
in Technique[技术] by (71.8m points)

C++: Template Specialization causes different result in Debug / Release

In the following code, I create a Builder template, and provide a default implementation to return nothing. I then specialize the template with int, to return a value 37.

When I compile with -O0, the code prints 37, which is the expected result. But when I compile using -O3, the code prints 0.

The platform is Ubuntu 20.04, with GCC 9.3.0

Can anyone helps me understand the behavior?

builder.h

class Builder {
        public:
                template<typename C>
                static C build() {
                        return 0;
                }
};

builder.cc

#include "builder.h"

template<>
int Builder::build<int>() {
        return 37;
}

main.cc

#include "builder.h"
#include <iostream>

int main() {
        std::cout << Builder::build<int>() << '
';
}

makefile

CXX_FLAG = -O0 -g
all:
        g++ $(CXX_FLAG) builder.cc -c -o builder.o
        g++ $(CXX_FLAG) main.cc builder.o -o main
clean:
        rm *.o
        rm main
question from:https://stackoverflow.com/questions/65876360/c-template-specialization-causes-different-result-in-debug-release

与恶龙缠斗过久,自身亦成为恶龙;凝视深渊过久,深渊将回以凝视…
Welcome To Ask or Share your Answers For Others

1 Reply

0 votes
by (71.8m points)

You should add a forward declaration for build<int>() to builder.h, like so:

template<>
int Builder::build<int>();

Otherwise, while compiling main.cc, the compiler sees only the generic template, and is allowed to inline an instance of the generic build() function. If you add the forward declaration, the compiler knows you provided a specialization elsewhere, and will not inline it.

With -O3, the compiler tries to inline, with -O0 it will not inline anything, hence the difference.

Your code actually violates the "One Definition Rule": it will create two definitions for Builder::build<int>(), but they are not the same. The standard says the result is undefined, but no diagnostics are required. That is a bit unfortunate in this case, as it would have been helpful if a warning or error message was produced.


与恶龙缠斗过久,自身亦成为恶龙;凝视深渊过久,深渊将回以凝视…
OGeek|极客中国-欢迎来到极客的世界,一个免费开放的程序员编程交流平台!开放,进步,分享!让技术改变生活,让极客改变未来! Welcome to OGeek Q&A Community for programmer and developer-Open, Learning and Share
Click Here to Ask a Question

...