无效类型的使用无效(链式模板类)

时间:2016-04-13 01:59:50

标签: c++ templates typedef

我正在尝试创建一个文件系统接口,以便我的微控制器可以与SD卡连接(我决定从头开始实现所有文件系统的东西)。问题是我不知道卡上会有什么文件系统....它可能是FAT16,FAT32,NFTS,ext3等。

所以我创建了以下抽象类:FileSystem FileDirectory。现在这一切都很好,但是我在微控制器上,所以我想避免使用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)

现在为了传递这个,我有一个名为FileSystemUnionFSU的结构。这基本上只定义了所有必要的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

所以真正的问题是:我该怎么做才能使这项工作成功?我愿意稍微重组一下,但经过几个小时的努力,我能想到的一切,我几乎已经准备好废弃整个事情并重新开始。

1 个答案:

答案 0 :(得分:2)

问题在于,在某些代码位置,您的类实际上是不完整的。

根据[class.mem] / 1:

  

类说明符的结束},类被视为完全定义的对象类型(3.9)(或完整类型)。   在类 member-specification 中,该类在函数体内被视为完整,   默认参数, using-declarations 引入继承构造函数(12.9), exception-specifications ,以及    brace-or-equal-initializers 用于非静态数据成员(包括嵌套类中的这类内容)。除此以外   它在自己的类 member-specification 中被认为是不完整的。

当应用于您的代码时,这尤其意味着该类在函数参数列表中是不完整的。现在让我们看一下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> convFSU<int,DFS,DFS>,因此实例化它涉及实例化UnionBase s内部,甚至是这个:

static_assert(AllInheritFrom<Base,Rest...>::value, "All of the elements of UnionBase must have Base as a public base");

其中一个类是DDirectory<int,thing>。请记住,所有这些都是在推断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&) {
    }
};