Warning: file_get_contents(/data/phpspider/zhask/data//catemap/6/cplusplus/140.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
C++ 模板类指针的强制转换_C++_Templates_Pointers - Fatal编程技术网

C++ 模板类指针的强制转换

C++ 模板类指针的强制转换,c++,templates,pointers,C++,Templates,Pointers,为了向界面用户隐藏实现细节,并避免广泛使用模板化函数,我想到了以下概念: //数据.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_ \

为了向界面用户隐藏实现细节,并避免广泛使用模板化函数,我想到了以下概念:

//数据.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_
\ifndef数据_
#定义数据_
#包括
模板
类数据
{
公众:
常数大小;
大小_t值[N];
数据();
};
#endif//DATA\u 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>;
#包括“data.h”
模板数据::数据()
:
n(n),
值()
{
对于(尺寸i=0;i
//清单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_
\ifndef列表_
#定义列表_
#包括
#包括
班级名单
{
私人:
std::共享的ptr数据;
公众:
列表(常数大小);
void printData()常量;
};
#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";
}
#包括“list.h”
#包括
#包括
#包括“data.h”
列表::列表(常数大小)
:
数据()
{
开关(n)
{
案例1u:
data=std::static_pointer_cast(std::make_shared());
打破
案例2u:
data=std::static_pointer_cast(std::make_shared());
打破
违约:
抛出std::runtime_错误(“未实例化…”);
}
}
无效列表::printData()常量
{
auto obj=std::static_pointer_cast(数据);//我的问题是关于这个
标准::cout n;++i)
{

std::cout values[i]是的。这是不安全的。任何时候通过
void*
进行强制转换都会有UB的风险。编译器不会就此向您发出警告,因为它不再具有执行此操作所需的类型信息。因此,您必须强制转换为正确的类型,而您没有这样做

从技术上讲,你在这里造成了未定义的行为。然而,我打赌它通常会起作用。这和你在C语言中必须一直做的一些胡扯没什么不同

它可以工作的原因是,实例的二进制布局可能是相同的。首先是“n”,如果你在做这个讨厌的把戏,你确实需要这个“n”,然后是数组的开头

如果你在指针领域之外做这件事,那你就要自讨苦吃了

正确删除对象的唯一原因是,shared_ptr在创建时创建了一个默认的删除器,因此它知道如何删除正确的类型。如果尝试此操作,任何其他智能指针都会导致各种类型的B

编辑:


现在,一个更好的方法是放弃使用类型系统来调整数组大小。如果您真的想要运行时分配的数组,请使用运行时系统来创建它!反正您是在免费存储上创建的,因此您不会从这样滥用类型系统中获得任何好处。您可以使用安全、可预测、标准的behavior如果您只是根据传递给列表构造函数的大小分配数组。

您拥有的是在编译时解析的静态转换。因此,您告诉编译器的是:

auto obj = std::static_pointer_cast<Data<>>(data); 
然后保留一个接口类型列表,只需使用
data->GetDataSize();


此外,不要将模板实现放在.cpp文件中,它们需要在使用它们的地方被看到。

我希望您意识到数据类中的
常量大小\u t n
是完全不需要的。您将该值作为模板参数列表的一部分,即
n
@WhozCraig
obj->n
如何使用它模板参数?std::static\u pointer\u cast将始终转换为数据…这就是您要问的吗?“感觉有点不安全。是否可以保证使用了正确的实例化?”--为什么实现神奇地知道正确的类型?不,这不安全,不要这样做。您需要添加一个返回
N
的方法。如果模板实现是唯一使用它的地方,那么将其放入cpp文件中是非常合适的。@CrazyEddie Yeap,但在这种情况下它不在使用它的地方。如果它与C99类似,则会内存布局保证允许您通过不同类型(对
struct sockaddr
和friends有用)访问主要公共字段,但我不确定这是否保证对数组有效(更不用说零长度数组了)。在任何情况下,我强烈怀疑订阅零长度数组是错误的(除非C++将它当作C99的可变长度数组)。@ TC -是的,我也不知道。我怀疑C++把它当作一个可变长度数组。事实上C++中的数组访问有比C更大的限制(比如整个数组[ON-PASTYXEDRON ])。.无论如何,这是对类型系统的严重滥用,必然会造成问题…如果团队成员在看到它时会不断地使用WTF 0_o的话。我当然不鼓励这样做,但我认为它通常会起作用。我也不认为它是如何实用的,因为你必须在编译时知道所有需要的列表大小时间
auto obj = std::static_pointer_cast<Data<>>(data); 
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; }
};