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

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>() << '\n';
}
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

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.

Related

Clang Warning on expression side effects

Given the following source code:
#include <memory>
#include <typeinfo>
struct Base {
virtual ~Base();
};
struct Derived : Base { };
int main() {
std::unique_ptr<Base> ptr_foo = std::make_unique<Derived>();
typeid(*ptr_foo).name();
return 0;
}
and compiled it with:
clang++ -std=c++14 -Wall -Wextra -Werror -Wpedantic -g -o test test.cpp
Enviroment setup:
linux x86_64
clang version 5.0.0
It does not compile because of warning (note -Werror):
error: expression with side effects will be evaluated
despite being used as an operand to 'typeid'
[-Werror,-Wpotentially-evaluated-expression]
typeid(*ptr_foo).name();
(Just a note: GCC does not claim that kind of potential problematic)
Question
Is there a way to get the information about the type pointed by a unique_ptr without generating that kind of warning?
Note: I am not talking about disabling -Wpotentially-evaluated-expression or avoiding -Werror.
Looks like following should work without warnings and give correct result for derived class
std::unique_ptr<Foo> ptr_foo = std::make_unique<Bar>();
if(ptr_foo.get()){
auto& r = *ptr_foo.get();
std::cout << typeid(r).name() << '\n';
}

different behavior depending on the optimization options

I found an example where the output is different depending on the optimization settings (-O3 vs none), yet GCC 4.8.2 produces no warnings, even with the -std=c++11 -Wall -pedantic options.
In this particular case, I'm assuming that "forgetting" the commented line in header.h is a mistake, and with -O3, c<int>::get() gets inlined.
However, is there any way to protect yourself against these kinds of mistakes -- a compiler or linker option perhaps?
header.h:
#ifndef HEADER_H
#define HEADER_H
template<class T>
struct c
{
int get() { return 0; }
};
// template<> int c<int>::get();
#endif
imp.cpp:
#include "header.h"
template<>
int c<int>::get()
{
return 1;
}
main.cpp:
#include <iostream>
#include "header.h"
int main()
{
c<int> i;
std::cout << i.get() << '\n'; // prints 0 with -O3, and 1 without
}
build:
c++ -std=c++11 -pedantic -Wall -O3 -c imp.cpp
c++ -std=c++11 -pedantic -Wall -O3 -c main.cpp
c++ -std=c++11 -pedantic -Wall -O3 imp.o main.o
What you get if you have the line in your header-file, is a declaration of an explicit specialization for that member-function.
Thus, main.cpp is assured of a definition in some other compilation-unit, and things work.
If you leave it out, you have a violation of the ODR:
That specific instantiation of your class-template is different in the compilation-units. Resulting in "ill-formed, no diagnostic required", so anything goes.
And there is (currently?) no compiler-option to force gcc to diagnose it.
The true mistake here is the way you're laying out your source files and building them. When c<int>::get() is used, its definition should be available in order to instantiate the template. To fix this, header.h should #include "imp.cpp" rather than the other way around. You may want to rename imp.cpp to imp.inl or something else.
When you define templates which are used outside of a single .cpp file, those definitions should be visible to anyone who includes their header.
As an aside: I don't think there's any way to make the compiler or linker warn you about what you've done here. But if you structure your project as I've described, this problem won't happen, because the forward declaration will be unnecessary.

gcc/g++ internal error (c++ templated lambda)

i was just making a few changes to my program, when all of a sudden g++ complained with an internal compiler error.
Clang however compiles it without any problems and also does not give any warnings, that would indicate anything weird.
I distilled the problem down to this:
#include <functional>
template<typename T>
class A{
T someVar;
};
template<typename T>
class B {
int x;
std::function<A<double>(A<int>&)> someLambda = [&](A<int>& aInt){
int xVar = x;
A<double> aRet;
return aRet;
};
};
int main(int argc, char** argv){
B<int> a;
return 0;
}
I tried both GCC 4.9.2 and 4.8.4, with both failing (internal compiler error).
Flags I used:
g++ -std=c++11 -O0 -g -Wall main.cpp -o gccBin
clang++ -std=c++11 -O0 -g -Wall main.cpp -o clangBin
main.cpp: In instantiation of 'struct B<int>::<lambda(class A<int>&)>':
main.cpp:10:7: required from here
main.cpp:14:24: internal compiler error: in tsubst_copy, at cp/pt.c:12569
int xVar = x;
^
libbacktrace could not find executable to open
Please submit a full bug report,
with preprocessed source if appropriate.
See <http://gcc.gnu.org/bugs.html> for instructions.
Clang++(3.5.1) compiles it without a problem, as I mentioned.
I also tried multiple machines, everywhere the same.
Is there some kind of error I overlooked? I searched a bit on the internet and the only similar problems i could find should have been fixed by now (as the bugtracker states).
Could maybe someone try and run this code on their machine or give other advice?
Thank you,
Lazarus
It's a compiler bug. Just go ahead and file a bug report to the GCC dudes!

Is there a way to know if exceptions have been disabled?

Is there a way to know if exceptions have been disabled in C++?
I'm developing an application that uses exceptions and I want to avoid having the user compile the application with exceptions disabled, like a warning that you need exceptions.
The standard certainly does not entertain such a functionality.
Assuming you are using a modern and competent compiler to compile code that contains a throw, then the compiler will error. But you can of course compile one part of the code WITH exceptions, and another without, in which case you still get exceptions thrown, but no way of catching them (since there is no catch either). So the program will probably terminate on first exception being thrown.
If you supply headers, you could just add a dummy function in an unnamed namespace:
namespace {
inline void dummy_dummy_my_thing_to_check_exceptions()
{
throw 123;
}
}
and never even call that function, it will still fail to compile.
I doubt that any compiler that lets you turn off exceptions will accept code that does this - I have tried with g++ 4.8.2, g++ 4.6.3, clang++ 3.6.0 (as of three weeks ago) and clang++ 2.9. All give an error for the above function inside a headerfile. If I remove -fno-exceptions, the code compiles and runs (with a terminate becuase the code does throw 1 in a function.
Total code:
x.h:
extern int func();
namespace {
inline void dummy_dummy_my_thing_to_check_exceptions()
{
throw 123;
}
}
x.cpp:
int func()
{
throw 1;
}
except.cpp:
#include "x.h"
int main()
{
func();
}
Compiles with:
g++ -c except.cpp && g++ except.o x.cpp
or
clang++ -c except.cpp && clang++ except.o,
but won't compile with:
g++ -c except.cpp -fno-exceptions && g++ except.o x.cpp
or
clang++ -c except.cpp -fno-exceptions && clang++ except.o.

template specialization in another file c++. Which version gets

I have these files :-
1.h :-
#include <iostream>
using namespace std;
template <typename A>
void f() {
cout<<"generic\n";
}
1.cpp :-
#include "1.h"
template <>
void f<int> () {
cout<<"for ints only\n";
}
main.cpp :-
#include "1.h"
int main() {
f<int>();
return 0;
}
Now, I compile and run these with g++ like this :-
g++ -c 1.cpp -o 1.o
g++ main.cpp 1.o
./a.out
And I get :-
for ints only
On the other hand, I compile it with icpc like this :-
icpc -c 1.cpp -o 1.o
icpc main.cpp 1.o
./a.out
And I get :-
generic
What does the C++ standard say about this? Is any one compiler "right" and the other "wrong" or is the standard ambiguous on this issue and both are "right" ?
Your program exhibits undefined behavior. The specialization must be declared in every translation unit in which it is used, per C++11 ยง14.7.3/6:
If a template, a member template or a member of a class template is explicitly specialized then that specialization shall be declared before the first use of that specialization that would cause an implicit instantiation to take place, in every translation unit in which such a use occurs; no diagnostic is required.