首先,我知道这个问题似乎是重复的。但我读过许多类似问题的帖子,但没有找到答案。
第二,到目前为止,我对我的解决方案没有任何问题。所以我要问的是,我的解决方案是否正确,没有陷阱。
假设我有一个类模板Particle,它应该是CRTP中的一个基类,并且打算有一个静态变量fName,可能因实例而有所不同。
基座
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";因此,其他粒子从该类继承(并实例化)。假设用户创建了一个新的Particle,他们应该可以选择是否指定新粒子的名称。在后一种情况下,名称应该是"Unknown"。
未命名粒子
Tachyon.h
#pragma once
#include "Particle.h"
class Tachyon : public Particle<Tachyon>
{
public :
Tachyon();
~Tachyon() = default;
};在Tachyon.cpp中没有什么特别之处(我创建.cpp文件是为了检查ODR是否被违反)。
另一方面,如果要指定名称怎么办。他们应该怎么做?
命名粒子
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;
}正如我所说的,我没有任何错误,程序按预期工作。但我对CRTP + ODR +静态数据成员声明/定义的组合有点困惑,所以问题就来了。
发布于 2021-10-10 17:56:15
目前还不清楚您认为这可能违反什么规则,但是这个程序是格式良好的。特别是,模板化的静态变量的显式专门化只有在具有初始化器的情况下才是定义(tem.ex.spec/14)。(非成员变量模板使用extern只声明专门化。)在声明显式专门化之前,也不需要使用主模板,只要派生类不这样做。
尽管如此,在这里您可以很容易地避免使用专门化:使用SFINAE检测成员的 fName,如果没有,则返回"Unknown"。或者,只需将fName作为CONCRETE_PARTICLE::fName来使用在那里声明的任何内容。(顺便说一句,不要对模板参数使用MACRO_NAMES。)
https://stackoverflow.com/questions/69510119
复制相似问题