4

First of all, I've got a header file for a class, an specialization declaration without definition(code samples from internet)

$ cat foo.h

template<typename T>
class foo{
public:
  static void init(){
      return;
  }

};

template<>  void foo<int>::init();

Then there're 2 implementation files for template specialization

$ cat foo_int.cpp 
#include "foo.h"
#include<stdio.h>
template<>
void foo<int>::init(){
    printf("init int foo\n");
}

$ cat foo_float.cpp 
#include "foo.h"
#include<stdio.h>
template<>
void foo<float>::init(){
    printf("init float foo\n");
}

Finally I got a main file

$ cat main.cpp
#include "foo.h"

int main(){
  foo<int>::init();
  foo<float>::init();
}

If I compile it without optimization and run it, it gives:

g++ foo_int.cpp foo_float.cpp main.cpp && a.out
init int foo
init float foo

If I add optimization, then the result is different:

$ g++ foo_int.cpp foo_float.cpp main.cpp -O2 && a.out
init int foo

The result is different. Some explanation from internet said this is due to some internal mechanism of "weak symbol" in gcc implementation, but my question:

  1. Is "weak symbol"/"strong symbol" a concept of gcc/g++, or it's part of the c/c++ language specification.

  2. If debug and release results are different, should I say this is a bug/issue of gcc/g++, in regard with "weak symbol" mechanism? As a developer, I wouldn't expect my debug version to behave differently from release version.

I tried clang, unfortunately same error. Is this an "acceptable" case for C/C++ that debug/release "should" behave so differently?

Community
  • 1
  • 1
Troskyvs
  • 7,537
  • 7
  • 47
  • 115
  • Declaration of specialization of `void foo::init()` is not visible in `main`... Your program is ill formed. – Jarod42 Oct 11 '16 at 11:35
  • Be careful when formatting the text. Only code blocks preserve white spaces and line breaks. When you pasted the `g++` console output under the `>` markup, it ignored line breaks all got squashed in to a one line of text. To preserve line breaks, put a double-space at the end of each line. Or just paste is as a code block. Readers usually have no problems in noticing which one contains code and which one contains console dump :) – quetzalcoatl Oct 11 '16 at 11:38
  • "I've got a header file for a class" -- no, you've got a header file for a **template**. – Pete Becker Oct 11 '16 at 11:39
  • declare the header of the explicit instantiation in the header file or use `extern template` – Guillaume Racicot Oct 11 '16 at 13:03

2 Answers2

6

The language definition requires that you declare an explicit specialization before it is used:

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. [temp.expl.spec]/6.

There is no declaration of the explicit specialization of foo<float>::init() at the point where it is called from main, but there is an explicit specialization in foo_float.cpp, so the behavior of the program is undefined.

Pete Becker
  • 74,985
  • 8
  • 76
  • 165
4

You've violated the one definition rule — your program contains two definitions of foo<float>::init.

One definition occurs in the compilation unit foo_float.cpp, and the other appears in the compilation unit main.cpp.

Violating the one definition rule means undefined behavior — in this case, what likely happens is:

  • With optimizations off, the program generates an actual function call, and the linker happened to put foo_float.cpp's version of the function in the executable.
  • With optimizations on, when compiling main.cpp the compiler inlined the function — naturally, it would inline main.cpp's version of the function.
  • In main.cpp: because there is no `foo::init` specialization declaration, then the general one is considered definition for `foo::init`? Is this the reason? – bolov Oct 11 '16 at 11:41