2

below is my code:

// types.h
template <typename T>
struct type_to_char {};

template <>
struct type_to_char<char> {
  static constexpr char str[] = "baz";
};


// main.cpp
#include <iostream>
#include <string>

#include "types.h"

int main() {
  std::cout << type_to_char<char>::str << std::endl;
    return 0;
}

On an attempt to compile, the linker returns an error: undefined reference to type_to_char<char>::str

I have encountered this answer, but I am not sure how to apply it in my case, since templates are not compiled. Should I put a seperate .cpp file in the project?

What is the difference between declaration and definition for constexpr variables? Such variable cannot be declared without an initializer, so why should I put a separate definition in a .cpp file?

I would appreciate some clarification on this

Community
  • 1
  • 1
Jytug
  • 1,072
  • 2
  • 11
  • 29

3 Answers3

2

Since you are fully specializing a class, it behaves like an untemplated class in many regards. One example is that it's static members have to be instantiated in an implementation file just like non-templated classes.

// header file (type.h)
template <typename T>
struct type_to_char {};

template <>
struct type_to_char<char> {
  static constexpr char str[] = "baz";
};

// impementation file (type.cpp)
constexpr char type_to_char <char>::str[];

// main.cpp
#include <iostream>
#include <type.h>

int main() {
    std::cout << type_to_char<char>::str << std::endl;
    return 0;
}
François Andrieux
  • 28,148
  • 6
  • 56
  • 87
1

You need to provide a definition in a .cpp that is linked in your final program. For example:

   // types.h
    template <typename T>
    struct type_to_char {};

    template <>
    struct type_to_char<char> {
      static constexpr const char str[] = "baz";
    };


    // main.cpp
    #include <iostream>
    #include <string>
    #include "types.h"

    constexpr const char type_to_char <char>::str[]; 

    int main() {
      std::cout << type_to_char<char>::str << std::endl;
    }
0

You cannot odr-use a static constexpr data member unless you provide a definition for it.
An attempt to odr-use it is what happens when you try to do this:

std::cout << type_to_char<char>::str << std::endl;

And that's why a definition is required.
You can easily reproduce the issue as it follows:

struct S { static constexpr int x = 0; };
int main() { auto y = &S::x; (void)y; }

Anyway, in your specific case, it's suffice to use the following declaration:

static constexpr char *str = "baz";

If you can use it instead of an array type, you don't have to explicitly define type_to_char<char>::str.

skypjack
  • 49,335
  • 19
  • 95
  • 187