MWB
MWB

Reputation: 12567

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

Upvotes: 3

Views: 189

Answers (2)

Deduplicator
Deduplicator

Reputation: 45654

  1. 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.

  2. 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.

Upvotes: 6

John Zwinck
John Zwinck

Reputation: 249093

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.

Upvotes: 0

Related Questions