First of all, I know this question might seem a duplicate. But I've read many posts with a similar question and didn't find an answer.
Second of all, I haven't had any issue with my solution so far. So I'm asking rather if my solution is a correct one with no pitfalls.
Suppose I have a class template Particle
which is supposed to be a base class in the CRTP and is intended to have a static variable fName
which may differ from instance to instance:
Base
Particle.h
#pragma once
#include <iostream>
#include <string>
template<typename CONCRETE_PARTICLE>
class Particle
{
private :
static const std::string fName;
public :
static const std::string& GetName() { return fName; }
};
// Default name. If I'm not mistaken this is fine regarding ODR.
template<typename CONCRETE_PARTICLE>
const std::string Particle<CONCRETE_PARTICLE>::fName = "Unknown";
So other particles inherit (and instantiate) from this class. Suppose the user creates a new Particle
and they should have a choice either to specify a name of their new particle or not. In the latter case the name would be "Unknown"
.
Unnamed particle
Tachyon.h
#pragma once
#include "Particle.h"
class Tachyon : public Particle<Tachyon>
{
public :
Tachyon();
~Tachyon() = default;
};
with nothing special in the Tachyon.cpp
(I made .cpp
files in order to check that ODR isn't violated).
On the other hand, what if the name is to be specified. What should they do?
Named particle
Muon.h
#pragma once
#include "Particle.h"
class Muon : public Particle<Muon>
{
public :
Muon();
~Muon() = default;
};
// Specification declaration (???)
// Tell the compiler that Particle<Muon>::fName is defined somewhere
// and not to take the default value into account (???)
template<>
const std::string Particle<Muon>::fName;
Muon.cpp
#include "Muon.h"
Muon::Muon() {}
template<>
const std::string Particle<Muon>::fName = "Muon";
Main.cpp
#include "Muon.h"
#include "Tachyon.h"
int main()
{
std::cout << Particle<Muon>::GetName() << "\n"; // prints "Muon"
std::cout << Particle<Tachyon>::GetName() << "\n"; // prints "Unknown"
return 0;
}
As I said I don't get any error and the program works as intended. But I am a bit confused by the mix of CRTP + ODR + static data member declaration/definition so the question.