转换指向模板类的指针
Cast of pointers to template classes
为了对接口用户隐藏实现细节并避免模板化函数的广泛使用,我想到了以下概念:
//data.h#ifndef DATA_H_
#define DATA_H_
#include <cstddef>
template <size_t N = 0>
class Data
{
public:
const size_t n;
size_t values[N];
Data<N>();
};
#endif // DATA_H_
//data.cpp #include "data.h"
template <size_t N> Data<N>::Data()
:
n(N),
values()
{
for ( size_t i = 0; i < n; ++i )
{
values[i] = i;
}
}
template class Data<1u>;
template class Data<2u>;
//list.h #ifndef LIST_H_
#define LIST_H_
#include <cstddef>
#include <memory>
class List
{
private:
std::shared_ptr<void> data;
public:
List(const size_t);
void printData() const;
};
#endif // LIST_H_
//list.cpp #include "list.h"
#include <iostream>
#include <stdexcept>
#include "data.h"
List::List(const size_t n)
:
data()
{
switch ( n )
{
case 1u:
data = std::static_pointer_cast<void>(std::make_shared<Data<1u>>());
break;
case 2u:
data = std::static_pointer_cast<void>(std::make_shared<Data<2u>>());
break;
default:
throw std::runtime_error("not instantiated..");
}
}
void List::printData() const
{
auto obj = std::static_pointer_cast<Data<>>(data); // my question is about this
std::cout << obj->n << ": ";
for ( size_t i = 0; i < obj->n; ++i )
{
std::cout << obj->values[i] << " ";
}
std::cout << "n";
}
//main.cpp #include "list.h"
int main()
{
for ( size_t i = 1; i <= 2; ++i )
{
try
{
List list(i);
list.printData();
}
catch ( ... )
{
return 1;
}
}
}
我知道有些人可能会认为这是一个可怕的设计。请不要在这里讨论这个,除非你有一个绝妙的选择。
我的问题是关于List::printData()
中的auto obj = std::static_pointer_cast<Data<>>(data);
行。感觉有点不安全。是否有保证使用了正确的实例化?g++-4.6.3
不给这个代码一个警告,它打印预期的值
是。它是不安全的。任何时候你通过一个void*
铸造你有UB的风险。编译器不会警告您,因为它不再具有这样做所需的类型信息。因此,转换为正确的类型是您的责任,而您并没有这样做。
它能够工作的原因是实例的二进制布局可能是相同的。首先是'n',如果你要做这个讨厌的把戏,你确实需要它,然后是数组的开头。
如果你在指针领域之外这样做,那你就完蛋了。
对象被正确删除的唯一原因是shared_ptr在创建时创建了一个默认的删除器,因此它知道如何删除正确的类型。如果你尝试这个,任何其他智能指针都会引起各种各样的废话。
编辑:现在,一个更好的方法是放弃使用类型系统来调整数组的大小。如果你真的想要一个运行时分配的数组,使用运行时系统来创建它!无论如何,你是在免费商店中创建它的,所以你不会从像这样滥用类型系统中得到任何好处。如果你只是根据传递给列表构造函数的大小来分配数组,你就可以拥有安全的、可预测的、标准的行为。
这里有一个在编译时解析的static_cast。所以你告诉编译器的是:
auto obj = std::static_pointer_cast<Data<>>(data);
static_pointer_cast
将变量 data
改为类型 std::shared_ptr<Data<>>
。
默认情况下(正如您在模板原型中声明的那样),Data<>
表示Data<0>
。
所以你总是会得到相同类型的shared_pointer
。
你能做的就是做一个接口,然后在运行时得到它的大小。
class IData
{
virutal size_t GetDataSize() = 0;
}
template <size_t N = 0>
class Data : public IData
{
public:
const size_t n;
size_t values[N];
Data<N>();
virtual size_t GetDataSize() override { return N; }
};
然后保持一个列表的接口类型,只使用data->GetDataSize();
此外,不要把模板实现放在.cpp文件中,它们需要在使用它们的地方被看到。
- 正在将指针转换为范围
- 如何理解将半精度指针转换为无符号长指针和相关的内存对齐
- C++:Lambda 函数指针转换的用例是什么?
- 如何将 int 指针转换为浮点指针
- 为什么在将 void 指针转换为整数指针时出现分段错误
- 将(N 个字节)无符号字符指针转换为浮点数和双 C++
- 我们可以在不知道其真实类型的情况下将基类指针转换为派生类指针吗?
- C++中数组大小未知的指针转换
- Antlr cpp 运行时 任何错误的指针转换?
- std::flush可以用于将对象指针转换为其封闭数组指针吗
- C 指针转换会导致内存访问冲突
- 模板类实例化中的指针转换无效
- 函数调用歧义(用户定义的转换和 Derived2Base 指针转换)
- 如何将 void(*)() 类型的指针转换为 void*
- 数组到指针转换期间的临时具体化
- 直接为浮点变量分配十六进制整数与通过指针转换分配之间的区别
- 将基类指针转换为派生的类指针
- 应对 std::字符串中的 std::<char>指针转换后的向量
- 在编译时将函数指针转换为 std::uintptr_t
- 将基类指针转换为未知派生类指针