【发布时间】:2021-11-29 06:06:55
【问题描述】:
首先,我知道这个问题可能看起来是重复的。但是我已经阅读了很多类似问题的帖子,但没有找到答案。
其次,到目前为止,我的解决方案没有任何问题。所以我要问的是我的解决方案是否是一个没有缺陷的正确解决方案。
假设我有一个类模板Particle,它应该是CRTP 中的一个基类,并打算有一个静态变量fName,它可能因实例而异 :
基础
粒子.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)。
另一方面,如果要指定名称怎么办。他们应该怎么做?
命名粒子
介子.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;
介子.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 + 静态数据成员声明/定义的组合有点困惑。
【问题讨论】:
-
我投票结束这个问题,因为这应该在 softwareengineering.stackexchange.com 上提问。
-
您可能想要删除那些默认的析构函数,因为它们会禁用编译器生成的移动构造函数/赋值:stackoverflow.com/questions/56968443/…。
-
@AVH,谢谢。会考虑的。
-
@cse 我不明白这与软件工程有什么关系。据我所知,这严格来说是一个与 ODR 相关的 C++ 问题。标题与问题有点不同,所以我已经编辑了它。
-
@cse 我不知道这个问题是否适合软件工程,但它绝对是本网站的主题。即使它适用于其他网站,也不是关闭问题的理由。
标签: c++ templates static crtp explicit-instantiation