首页 > 解决方案 > 根据其构成的类型的存在有条件地定义一个成员变量

问题描述

假设我有一个数据结构:

struct TestData {
}

和一个带有成员变量的类:

class TestContainer {
private:
  TestData data;
};

两者都是在一个用于多个测试文件的宏的 cpp 文件中定义的。

现在,如果没有定义 TestData 结构,我想在编译时删除数据成员。如果测试不需要数据,则无需定义数据成员(并且它会产生未使用的警告)。我想过使用std::enable_if,但没有想出一个条件。另一种方法是定义一个基本模板类和专业化,如this question所示,但是如何专门化一个类型的存在?

如何才能做到这一点?

标签: c++c++11

解决方案


如果您认为前向声明不存在,您可以检查结构是否存在。

此示例假定TestData始终定义或从未定义:

#include <type_traits>

// Comment this line to trigger the static assert
struct TestData {};

template<typename, typename = void>
struct MaybeData {};

template<typename T>
struct MaybeData<T, std::void_t<decltype(sizeof(T))>> {
    T data;
};

struct TestContainer : MaybeData<struct TestData> {};

我们可以像这样测试我们的解决方案:

template<typename, typename = void>
constexpr auto has_data = false;

template<typename T>
constexpr auto has_data<T, std::void_t<decltype(T::data)>> = true;

static_assert(has_data<TestContainer>);

这背后的机制不是将结构本身 ( TestData) 作为类型发送,而是struct TestData作为参数使用,如果类型存在则引用该类型,如果不存在则转发声明。

然后,我们使用 sfinae 来检查是否sizeof(T)是一个有效的表达式。如果TestData是不完整类型,则表达式无效。

然而,如果一个类型的完整性在模板的实例化之间发生了变化,那么程序是不正确的。

活生生的例子


推荐阅读