目录
- #include
-
- template <typename T, size_t N>
- struct NSVarTypeDict {
- static void Create_() {
- CreateHelper
(); - }
-
- private:
- template <size_t M, typename U>
- struct CreateHelper {
- static void Apply() {
- // 构造元素的逻辑
- std::cout << "Constructing element at index " << M << std::endl;
- CreateHelper
1, U>::Apply(); - CreateHelper
1, U>::Apply(); - }
- };
-
- template <typename U>
- struct CreateHelper<0, U> {
- static void Apply() {
- // 基础情况:当索引为0时停止递归
- }
- };
- };
-
- int main() {
- NSVarTypeDict<int, 8>::Create_();
- return 0;
- }
- #include
- #include
-
- template <size_t N, size_t M, typename T1, typename T2>
- struct NSVarTypeDict {
- using NewTupleType_ = std::conditional_t
; - };
-
- int main() {
- struct Type1 {
- int value;
- };
-
- struct Type2 {
- double value;
- };
-
- typename NSVarTypeDict<3, 4, Type1, Type2>::NewTupleType_ var1; // 选择Type2
- typename NSVarTypeDict<5, 5, Type1, Type2>::NewTupleType_ var2; // 选择Type1
-
- return 0;
- }
在使用std::conditional_t进行合并后,简化的代码更易于理解和维护,并且避免了重复代码的问题,因此整体上更具优势。
- #include
-
- class VarTypeDict {
- public:
- template<typename T>
- void Set(T&& value) && {
- // 只能用于右值的Set函数实现
- std::cout << "Setting value for rvalue: " << value << std::endl;
- }
-
- template<typename T>
- void Set(T& value) & {
- // 能用于左值的Set函数实现
- std::cout << "Setting value for lvalue: " << value << std::endl;
- }
- };
-
- int main() {
- VarTypeDict::Values values;
-
- int x = 10;
- values.Set(x); // 调用能用于左值的Set函数
- values.Set(20); // 调用只能用于右值的Set函数
-
- return 0;
- }
优势和劣势:
优势:
劣势:
总体上,能用于左值的函数相比只能用于右值的函数更加灵活,可以接受更多种类的参数,但需要谨慎使用以避免潜在的问题。
将构造函数的访问权限从public修改为private或protected是一种有效的封装手段,可以限制其它类对构造函数的直接访问,从而更好地控制类的实例化。
理由:
接下来,让我们尝试将Values的构造函数访问权限从public修改为private,然后编译检查是否符合预期。
- class VarTypeDict {
- public:
- class Values {
- private: // 修改构造函数的访问权限为private
- Values() {}
- friend class VarTypeDict; // 允许VarTypeDict类访问构造函数
- public:
- template<typename T>
- void Set(T&& value) && {
- std::cout << "Setting value for rvalue: " << value << std::endl;
- }
- template<typename T>
- void Set(T& value) & {
- std::cout << "Setting value for lvalue: " << value << std::endl;
- }
- };
- };
根据上述代码修改,我们将Values的构造函数的访问权限修改为private,并使用friend关键字允许VarTypeDict类访问构造函数。
在实际编译时,会发现尝试在外部进行Values类的实例化会导致编译错误,而在VarTypeDict类中可以正常调用构造函数来创建Values的实例,符合我们的预期。
这种修改符合我们的预期,成功限制了外部代码对Values类的直接实例化,增强了类的封装性和安全性。
- #include
- #include
-
- class VarTypeDict {
- public:
- class Values {
- private:
- std::tuple<int, double, std::string> data; // 使用std::tuple替换指针数组
- public:
- template<typename T>
- void Set(T&& value) && {
- std::get
(data) = value; // 使用std::get获取元素 - }
- template<typename T>
- T Get() {
- return std::get
(data); // 使用std::get获取元素 - }
- };
- };
示例中,使用std::tuple替换了指针数组,这样就不需要显式进行内存分配和释放。通过std::get函数,我们可以在不了解具体元素类型的情况下,访问和操作特定类型的元素。
新版本的复杂度分析:
总体而言,通过使用std::tuple替换指针数组,新版本的VarTypeDict复杂度并未明显增加,并且更加安全和易用,因为不再需要显式操作内存分配与释放,同时使用std::tuple提供了更好的类型安全性和代码可读性。
- #include
-
- // 定义策略类模板
- template <typename T>
- class Policy {
- public:
- void DoSomething() {
- std::cout << "Doing something with type " << typeid(T).name() << std::endl;
- }
- };
-
- // 定义宏来简化策略对象的定义
- #define POLICY_POLICY(PolicyType, ValueType) Policy
> -
- int main() {
- // 构造模板策略对象
- POLICY_POLICY(std::vector, int) policyObject;
-
- // 使用策略对象
- policyObject.DoSomething();
-
- return 0;
- }
- #include
- #include
- #include
-
- class NamedParameters {
- public:
- class Values {
- private:
- int value;
- public:
- Values(int val) : value(val) {}
-
- template<typename T>
- T Get() const {
- return T(value); // 复制构造返回值
- }
-
- template<typename T>
- typename std::remove_const
::type&& Get() && { - return std::move(value); // 返回右值引用,使用移动语义
- }
- };
- };
-
- int main() {
- NamedParameters::Values values(123);
-
- // 使用左值引用调用Get函数
- int copyValue = values.Get<int>();
- std::cout << "Copy Value: " << copyValue << std::endl;
-
- // 使用右值引用调用Get函数
- int&& moveValue = std::move(values).Get<int>();
- std::cout << "Move Value: " << moveValue << std::endl;
-
- return 0;
- }
示例中,我们在NamedParameters::Values类中引入了一个新的Get函数模板,并使用std::remove_const来移除返回类型的const限定符。在Get函数的右值引用版本中,我们使用std::move对底层数据对象进行移动,通过移动语义返回右值引用。这样,对于右值引用的情况,我们可以通过移动来返回底层数据对象,减少了额外的复制成本。
在主函数中,我们首先使用左值引用调用Get函数,对底层数据对象进行复制。然后,我们使用std::move将values对象转换为右值引用,并调用Get函数获取右值引用的底层数据对象。通过输出的结果,我们可以看到使用移动语义获取的值。
通过引入移动语义的Get函数,我们可以根据NamedParameters::Values对象的左值或右值特性,使用不同的方式返回底层数据对象,从而减少复制带来的额外消耗。
- #include
- #include
-
- // 定义异类词典模板
- template<typename... Ts>
- struct VarTypeDict {};
-
- // 添加元素的元函数 AddItem
- template <typename Dict, typename NewItem>
- struct AddItem;
-
- // 特化:向空的异类词典添加元素
- template <typename NewItem>
- struct AddItem
, NewItem> { - using type = VarTypeDict
; - };
-
- // 特化:向非空的异类词典添加元素
- template <typename Head, typename... Tail, typename NewItem>
- struct AddItem
, NewItem> { - using type = typename std::conditional
::value, - VarTypeDict,
- typename AddItem
, NewItem>::type>::type; - };
-
- // 删除元素的元函数 DelItem
- template <typename Dict, typename ItemToDelete>
- struct DelItem;
-
- // 特化:从空的异类词典删除元素,报错
- template <typename ItemToDelete>
- struct DelItem
, ItemToDelete> { - static_assert(sizeof(ItemToDelete) == 0, "Item does not exist in VarTypeDict");
- };
-
- // 特化:从包含元素的异类词典删除元素
- template <typename Head, typename... Tail, typename ItemToDelete>
- struct DelItem
, ItemToDelete> { - using type = typename std::conditional
::value, - VarTypeDict
, - typename AddItem<typename DelItem
, ItemToDelete>::type, Head>::type>::type; - };
-
- int main() {
- // 使用示例:添加元素
- using MyDict = VarTypeDict<struct A, struct B>;
- using DictWithMoreItems = typename AddItem
struct C>::type; - using DictWithLessItems = typename DelItem
::type; -
- // 使用示例:删除不存在的元素,会报错
- // using DictWithInvalidDel = typename DelItem
::type; // 会产生编译时错误 -
- std::cout << typeid(DictWithLessItems).name() << std::endl; // 输出 VarTypeDict
-
- return 0;
- }
示例中,我们定义了AddItem和DelItem两个元函数来实现添加和删除元素。通过模板特化和递归调用,我们可以实现对异类词典的元素操作。在DelItem的特化中,我们使用静态断言来检测是否要删除的元素存在于异类词典中,以便在编译时发现错误。
在主函数中,我们使用示例展示了AddItem与DelItem元函数的使用方式,并输出了修改后的异类词典类型。同时,我们还展示了尝试删除不存在的元素时会触发编译时错误的情况。
通过这种方式,我们可以在编译期间操作异类词典的元素,动态地修改异类词典的类型。
下一章开始学习深度学习简介!!!