11

Take the following piece of code:

#include <type_traits>
#include <iostream>

template <class T>
void print(T &&t){
    std::cout << t << std::endl;
}

template<class T, T val>
struct Foo{
    static constexpr T value = val;
};

int main(){
    print(Foo<int, 123>::value);
}

It refuses to compile under Clang 3.3 and GCC 4.8.1 ("undefined reference to Foo<int, 123>::value"), which puzzles me because Foo does exactly the same as std::integral_constant, and the same code runs fine with integral_constant. It also fails with plain lvalue reference in the print function. Any explanation regarding this behaviour?

The issue is also present with this quite minimal example:

template<class T>
struct Bar{
    static const bool value = true;
};
András Kovács
  • 29,931
  • 3
  • 53
  • 99
  • 3
    Your example compiles and runs [on Ideone](http://ideone.com/BJLEuL). Maybe a compiler issue? – djf Jun 30 '13 at 16:51
  • I edited in the compiler versions; Ideone probably uses older stuff. – András Kovács Jun 30 '13 at 16:53
  • Now this is quite interesting: http://www.compileonline.com throws the error but has gcc 4.7.2 just like Ideone. – András Kovács Jun 30 '13 at 17:03
  • 1
    Whether using `const` or `constexpr`, it compiles with `-O2` on g++4.8. But not without. Haha – Yohan Danvin Jun 30 '13 at 17:23
  • Clang's consistently not compiling through -O levels. – András Kovács Jun 30 '13 at 17:28
  • Also, if you use `cout` directly (no print(..)) it always compiles on g++. – Yohan Danvin Jun 30 '13 at 17:31
  • 5
    This might be a [duplicate](http://stackoverflow.com/questions/14547986/what-am-i-allowed-to-do-with-a-static-constexpr-in-class-initialized-data-memb). I think by binding it to a reference (universal -> `const&`, not rvalue) you odr-use the variable therefore it has to be defined. – dyp Jun 30 '13 at 17:42
  • Why does it compile with integral_constant, though? I just copied in its definition from the libstdc++ sources and it's not working in my source. – András Kovács Jun 30 '13 at 18:06
  • 2
    Maybe the libstdc++ provides a definition somewhere else? As a workaround you can use `+Foo::value` (unary plus) to force an rvalue ([thanks litb](http://stackoverflow.com/a/3182557/688659)). – gx_ Jun 30 '13 at 18:32

1 Answers1

4

As the compiler says, there is no reference to the static variable, you must add

template<class T, T val>
constexpr T Foo<T, val>::value;

after the definition of the class Foo

Stefano Falasca
  • 8,837
  • 2
  • 18
  • 24