无效使用不完整的类型(链接的模板类)
Invalid use of incomplete type (chained templated classes)
我正在尝试创建一个文件系统接口,以便我的微控制器可以与SD卡接口(我决定从头开始实现所有文件系统的东西)。问题是我不知道卡上的文件系统是什么。。。。可以是FAT16、FAT32、NFTS、ext3等。
因此,我创建了以下抽象类:FileSystem
File
和Directory
。现在一切都很好,但我使用的是微控制器,所以我想避免使用new
运算符。
这导致我创建了UnionBase
类(不是一个很有用的名称)。基本上,这个类包含所有不同派生类的并集,并允许您在它们之间进行转换:
struct BaseFile_t{
};
struct DerivedA : BaseFile_t{
};
struct DerivedB : BaseFile_t{
};
UnionBase<BaseFile_t,DerivedA,DerivedB> var; //Can now pass references
//of this into File system function
//so that they can modify the right
//Derived type (which can then be
//used as if it is the base type)
现在,为了传递这个信息,我有一个名为FileSystemUnion
或简称FSU
的结构。这基本上只是定义了所有必要的BaseUnion类型。
真正的问题是,如果递归typedef(我知道这是不允许的),它可能最终成为一个类型。这是我代码的缩短版本:
#include <stdio.h>
#include <iostream>
#include <string>
#include <conio.h>
#include <stdlib.h>
#include <fstream>
#include "prototypeInd/templates/UnionBase.h"
using namespace prototypeInd::templates;
template<class arg,class conv>
struct File{
};
template<class arg,class conv>
struct Directory : public File<arg,conv>{
};
template<class arg,class conv>
struct FS{
typedef Directory<arg,conv> Directory;
typedef File<arg,conv> File;
};
template<class arg,class conv>
struct DFile : public virtual File<arg,conv>{
};
template<class arg,class conv>
struct DDirectory : public virtual Directory<arg,conv>, public virtual DFile<arg,conv>{
void foo(typename conv::Directory::UnionType& d){
}
};
template<class arg,class conv>
struct DFS : public virtual FS<arg,conv>{
typedef DFile<arg,conv> File;
typedef DDirectory<arg,conv> Directory;
};
template<class arg,template<class,class> class fsa,template<class,class> class fsb>
struct FSU{
typedef UnionBase<FS<arg,FSU>,fsa<arg,FSU>,fsb<arg,FSU> > FS;
typedef UnionBase<typename ::FS<arg,FSU>::Directory,typename fsa<arg,FSU>::Directory,typename fsb<arg,FSU>::Directory> Directory;
typedef UnionBase<typename ::FS<arg,FSU>::File,typename fsa<arg,FSU>::File,typename fsb<arg,FSU>::File> File;
};
typedef FSU<int,DFS,DFS> thing;
DDirectory<int,thing> d;
int main(int d,char** thing){
}
我得到的错误是:invalid use of incomplete type 'struct DDirectory<int, FSU<int, DFS, DFS> >'
这是UnionBase.h(它很大,但不用担心,所有这些都在工作):
#ifndef prototypeInd_templates_UnionBase_h
#define prototypeInd_templates_UnionBase_h
#include <type_traits>
template<class Type, uint64_t time,class First,class... Array>
class IndexOf_{
static const bool isSame = std::is_same<First,Type>::value;
public:
static const uint64_t value = isSame ? time : IndexOf_<Type,time+1,Array...>::value;
};
template<class Type, uint64_t time, class First>
class IndexOf_<Type,time,First>{
public:
//static_assert(std::is_same<First,Type>::value,"Not contained in list");
static const uint64_t value = time;
};
template<class Type,class... Array>
using IndexOf = IndexOf_<Type,0,Array...>;
template<class Target, class First, class... Rest>
class ContainsType{
public:
static const bool value = std::is_same<Target, First>::value ? true : ContainsType<Target,Rest...>::value;
};
template<class Target, class First>
class ContainsType<Target,First>{
public:
static const bool value = std::is_same<Target, First>::value;
};
//Best is the highes so far while rest is the rest of the list
template <class Best,class First, class... Rest>
class GetMaxSize{
//typedef typename GetFirstType<Rest...>::value First;
static const bool FirstBigger = sizeof(First) > sizeof(Best);
public:
typedef typename std::conditional<FirstBigger,typename GetMaxSize<First,Rest...>::value,typename GetMaxSize<Best,Rest...>::value >::type value;
};
template<class Best, class First>
class GetMaxSize<Best,First>{
static const bool FirstBigger = sizeof(First) > sizeof(Best);
public:
typedef typename std::conditional<FirstBigger,First,Best >::type value;
};
template<class From,uint16_t index,class UT,class First,class... Array>
struct cast{
static void apply(From** t,UT* f){
if (index == f->GetActive()){
*t = &((First)(*f));
}
else{
cast<From,index+1,UT,Array...>::apply(t,f);
}
}
};
template<class From,uint16_t index,class UT,class First>
struct cast<From,index,UT,First>{
static void apply(From** t,UT* f){
if (index == f->GetActive()){
*t = &((First)(*f));
}
}
};
template<class... Values>
class UnionType{
typedef typename GetMaxSize<Values...>::value internal_t;
internal_t data;
uint16_t active;
public:
template<class CastFrom, class Dummy = typename std::enable_if<ContainsType<CastFrom,Values...>::value, int>::type >
UnionType(CastFrom&& d) : data(reinterpret_cast<internal_t&>(d)),active(IndexOf<CastFrom,Values...>::value){
}
template<class CastTo, class Condition = typename std::enable_if<ContainsType<CastTo,Values...>::value,int>::type >
operator CastTo const&() const{
return reinterpret_cast<const CastTo&>(data);
}
uint16_t GetActive() const{
return active;
}
//This one actually uses casting of the active data type
template<class CastTo, class Condition = typename std::enable_if<!ContainsType<CastTo,Values...>::value,int>::type >
explicit operator CastTo*() const{
CastTo temp;
CastTo* ret = &temp;
cast<CastTo,0,UnionType,Values...>::apply(&ret,this);
return ret;
}
};
namespace prototypeInd{namespace templates{
template<class Base, class Thing>
struct IsPublicBase{
static const bool value = std::is_base_of<Base,Thing>::value && std::is_convertible<Thing*,Base*>::value;
};
template<class Base, class First, class... Rest>
struct AllInheritFrom{
static const bool value = IsPublicBase<Base,First>::value ? AllInheritFrom<Base,Rest...>::value : false;
};
template<class Base, class First>
struct AllInheritFrom<Base,First>{
static const bool value = IsPublicBase<Base,First>::value;
};
template<template<class> class Function,class First,class... Args>
struct AllFullfill{
static const bool value = Function<First>::value ? AllFullfill<Function,Args...>::value : false;
};
template<template<class> class Function,class First>
struct AllFullfill<Function,First>{
static const bool value = Function<First>::value;
};
template<class Base, class... Rest>
class UnionBase{
static_assert(AllInheritFrom<Base,Rest...>::value, "All of the elements of UnionBase must have Base as a public base");
public:
typedef UnionType<Rest...> UnionType;
private:
UnionType internal;
public:
UnionBase() : internal(typename GetFirstType<Rest...>::value()){};
UnionBase(Base&& value) : internal(value){
}
operator UnionType&(){
return internal;
}
Base* operator ->() const{
//return 0;
return &((Base&)internal);
}
};
//template<class Base, class... Rest>
//using UnionBase = UnionBase_<Base,Rest...>*;
}}
#endif
所以真正的问题是:我应该怎么做才能让它发挥作用?我对重组持开放态度,但经过几个小时的尝试,我几乎准备放弃整个事情,重新开始。
问题是,在代码的某些地方,类确实是不完整的。
根据[class.mem]/1:
在类说明符的结束
}
处,类被视为完全定义的对象类型(3.9)(或完整类型)。在类成员规范中,该类在函数体中被视为完整的,默认参数,使用声明引入继承构造函数(12.9),异常规范,以及非静态数据成员(包括嵌套类中的此类内容)的大括号或相等的初始值设定项。否则它在其自己的类成员规范中被认为是不完整的。
当应用于代码时,这尤其意味着类在函数参数列表中是不完整的。现在让我们来看看DDirectory::foo()
:的定义
template<class arg,class conv>
struct DDirectory : public virtual Directory<arg,conv>, public virtual DFile<arg,conv>{
void foo(typename conv::Directory::UnionType& d){
}
};
在实例化DDirectory<int,thing>
中,conv
是FSU<int,DFS,DFS>
,因此它的实例化涉及内部UnionBase
的实例化,并且与此相关:
static_assert(AllInheritFrom<Base,Rest...>::value, "All of the elements of UnionBase must have Base as a public base");
其中一个类是CCD_ 15。记住,所有这些都发生在推导foo()
的参数类型时,所以DDirectory<int,thing>
是不完整的,这就是编译器所说的。
例如,你可以尝试将static_assert
移动到UnionBase
的构造函数中,但它并不能解决我认为不可能修复的其他错误,原因是一样的:
error: invalid application of 'sizeof' to an incomplete type 'DDirectory<int, FSU<int, DFS, DFS> >'
static const bool FirstBigger = sizeof(First) > sizeof(Best);
^~~~~~~~~~~~~
这里有一个最小化的例子再现了这个问题:
#include <type_traits>
template <typename T1, typename T2>
struct BiggerType {
using type = typename std::conditional<(sizeof(T1) > sizeof(T2)), T1, T2>::type;
};
template<typename T>
struct S {
using B = BiggerType<S, int>;
// This causes the instantiation of BiggerType,
// leading to calculation of sizeof(S) which is incomplete
void foo(const typename B::type& bt) {
}
};
int main() {
S<int> s;
}
或者以非常压缩的形式,
template<typename T>
struct S {
// Same problem here
void foo(typename std::conditional<(sizeof(S) > sizeof(int)), S, int>::type&) {
}
};
- 指向(数据)成员的指针作为非类型模板参数,例如具有自动存储持续时间/无链接
- 使用 trie 数据结构链接不同类型的信息
- 无法创建类型为无序链接列表的对象
- 解析参数值 - 字符串和链接值(类型字符串的链接值)与(特定类型的)变量
- 共享库中非模板基的模板子类导致未定义的符号类型信息'class'链接错误
- 如何将不同类型的节点存储在一个链接列表中
- 将模板类与引用非类型模板参数一起使用时出现链接器错误
- 类类型的静态constexpr字段在g++中给出链接时间错误
- 如何使用同一链接列表一次处理各种类型的节点
- 链接时错误地折叠了LLVM IR类型(C++API)
- C++11中具有C链接的复杂类型
- 为什么对非类型模板参数的引用需要外部链接
- 链接列表中的虚函数 - 多种返回类型(对象)
- 为什么我的链接数据类型复制构造函数不起作用?
- 为什么我得到的声明没有类型错误链接列表
- 如何为链接列表节点定义一个以指针为模板类型的模板类
- 无效使用不完整的类型(链接的模板类)
- 警告LNK4206:找不到预编译类型信息; 未链接或覆盖;链接对象,就好像没有调试信息一样
- 类型是否只有内部/外部链接以外的"链接"?
- 如何在CMake中指定链接类型