【发布时间】:2021-12-11 05:28:34
【问题描述】:
我创建了 Curiously Recurring Template Pattern 的 constexpr 版本,所有似乎都按预期工作,除了“在正常情况下”应标记为 virtual 的析构函数。据我了解,virtual 是constexpr 的死敌。
在我的示例中,我实现了两个没有数据成员的接口。在一般情况下(使用数据成员)是否正确让 virtual ~Crtp() = default;、virtual ~FeatureNamesInterface() = default; 和 virtual ~FeatureValuesInterface() = default; 注释掉并让编译器定义析构函数?这种方法有内存泄漏吗?保护它们是更好的方法吗?欢迎使用 constexpr 的任何其他解决方案!
接口代码如下所示
namespace lib
{
template <typename Derived, template<typename> class CrtpType>
struct Crtp
{
//virtual ~Crtp() = default;
[[nodiscard]] Derived& child() noexcept { return static_cast<Derived&>(*this); }
[[nodiscard]] constexpr Derived const& child() const noexcept { return static_cast<const Derived&>(*this); }
private:
constexpr Crtp() = default;
friend CrtpType<Derived>;
};
template<typename Derived>
struct FeatureNamesInterface : Crtp<Derived, FeatureNamesInterface>
{
constexpr FeatureNamesInterface() = default;
//virtual ~FeatureNamesInterface() = default;
[[nodiscard]] constexpr auto& GetFeatureNames() const noexcept { return Crtp<Derived, FeatureNamesInterface>::child().GetNames(); }
};
template<typename Derived>
struct FeatureDataInterface : Crtp<Derived, FeatureDataInterface>
{
constexpr FeatureDataInterface() = default;
//virtual ~FeatureValuesInterface() = default;
[[nodiscard]] constexpr auto GetFeatureData() const { return Crtp<Derived, FeatureDataInterface>::child()(); }
};
}
两个示例类的实现是这样的
namespace impl
{
class ChildOne final : public lib::FeatureNamesInterface<ChildOne>, public lib::FeatureDataInterface<ChildOne>
{
static constexpr std::array mNames{"X"sv, "Y"sv, "Z"sv};
public:
constexpr ChildOne() : FeatureNamesInterface(), FeatureDataInterface() {}
~ChildOne() = default;
[[nodiscard]] constexpr auto& GetNames() const noexcept { return mNames; }
[[nodiscard]] constexpr auto operator()() const noexcept
{
std::array<std::pair<std::string_view, double>, mNames.size()> data;
double value = 1.0;
for (std::size_t i = 0; const auto& name : mNames)
data[i++] = {name, value++};
return data;
}
};
class ChildTwo final : public lib::FeatureNamesInterface<ChildTwo>, public lib::FeatureDataInterface<ChildTwo>
{
static constexpr std::array mNames{"A"sv, "B"sv, "C"sv, "D"sv, "E"sv, "F"sv};
public:
constexpr ChildTwo() : FeatureNamesInterface(), FeatureDataInterface() {}
~ChildTwo() = default;
[[nodiscard]] constexpr auto& GetNames() const noexcept { return mNames; }
[[nodiscard]] constexpr auto operator()() const noexcept
{
std::array<std::pair<std::string_view, double>, mNames.size()> data;
double value = 4.0;
for (std::size_t i = 0; const auto& name : mNames)
data[i++] = {name, value++};
return data;
}
};
}
完整的例子可以在here找到。
【问题讨论】:
-
请注意,非 const
child()也可能是constexpr。 -
CRTP 与动态多态性相反的重点是避免虚函数,包括 dtor。
标签: c++ destructor compile-time crtp