代码之家  ›  专栏  ›  技术社区  ›  Flying Hat

如何处理参数包为空的情况

  •  4
  • Flying Hat  · 技术社区  · 9 年前

    我有以下代码用于获取包中所有基本类型的大小(我以特殊方式处理浮点和双精度),但当包为空时,我的程序无法编译。

    // terminating general case for T being anything else
    template <class T>
    size_t getSize()
    {
        return sizeof(T);
    }
    
    // terminating special case for T=double
    template<>
    size_t getSize<double>()
    {
        return SIZEOF_DOUBLE;
    }
    
    // terminating special case for T=float
    template<>
    size_t getSize<float>()
    {
        return SIZEOF_FLOAT;
    }
    
    // recursive case
    template <class T, class U, class ...S>
    size_t getSize()
    {
        return getSize<T>() + getSize<U, S...>();
    }
    

    我想要 getSize 返回 0 当像这样调用时

    template <class ...T>
    void foo(T... arg)
    {
        size_t sizeOfTypes = getSize<T...>();
    }
    

    具有 T={} ,即。 foo 被称为类似 foo<>(); .

    注意,我不想修改 食品 则尖括号必须保持在那里。最好我想要 获取大小 修改,因为我在除 食品 修改 食品 作为最后的手段。

    3 回复  |  直到 9 年前
        1
  •  3
  •   nh_    9 年前

    解决这个问题的另一种方法是使用一些小结构,如

    template<typename T>
    struct GetTypeSize
    {
        enum { value = sizeof(T) };
    };
    
    template<>
    struct GetTypeSize<float>
    {
        enum { value = SIZEOF_FLOAT };
    };
    
    template<>
    struct GetTypeSize<double>
    {
        enum { value = SIZEOF_DOUBLE };
    };
    
    template<typename...>
    struct GetSize 
    {
        enum { value = 0 };
    };
    
    template<typename Head, typename... Tail>
    struct GetSize<Head, Tail...>
    {
        enum { value = GetTypeSize<Head>::value + GetSize<Tail...>::value };
    };
    
    template<typename... T>
    void foo(T... arg)
    {
        size_t sizeOfTypes = GetSize<T...>::value;
    }
    

    这具有在编译时进行评估(总结)的优点。

    我使用了两种结构。一个用于执行递归(GetSize),另一个用于获取类型的实际大小(GetTypeSize)。专业化的 GetSize<Head, Tail...> 只要有头(包不是空的),就会实例化,并将头中类型的大小添加到 GetSize<Tail...> 。一旦没有Head,则使用回退GetSize模板。

    对于 GetSize<int, double, char> 结果是

    GetTypeSize<int>::value + GetTypeSize<double>::value + GetTypeSize<char>::value + GetSize<>::value

    那就是

    sizeof(int) + SIZEOF_DOUBLE + sizeof(char) + 0

        2
  •  3
  •   T.C. Yksisarvinen    9 年前

    首先是一个函数模板,它将单个类型转换为其大小,可能带有特殊化:

    template <class T>
    constexpr size_t getSize_single()
    {
        return sizeof(T);
    }
    
    template<>
    constexpr size_t getSize_single<double>()
    {
        return SIZEOF_DOUBLE;
    }
    
    template<>
    constexpr size_t getSize_single<float>()
    {
        return SIZEOF_FLOAT;
    }
    

    接下来,pack将类型包扩展为 std::initializer_list<size_t> 然后将其相加:

    template <class... Ts>
    constexpr size_t getSize() // constexpr for C++14 only - remove for C++11
    {
        std::initializer_list<size_t> l{getSize_single<Ts>()...};
        size_t sum = 0;
        for(auto s : l) sum += s;
        return sum;
    }
    

    的显式类型 initializer_list 需要处理空包装箱。

        3
  •  1
  •   Jahid Ramsy de Vos    9 年前

    如果您只想编辑getSize函数,那么将第一个函数的模板T初始化为void,并为void类型添加一个额外的模板函数以返回0。它将如下所示:

    template <class T=void> ////A little edit here
    size_t getSize()
    {
        return sizeof(T);
    }
    
    // terminating special case for T=double
    template<>
    size_t getSize<double>()
    {
        return SIZEOF_DOUBLE;
    }
    
    // terminating special case for T=float
    template<>
    size_t getSize<float>()
    {
        return SIZEOF_FLOAT;
    }
    /////Extra entry for void type
    template<>
    size_t getSize<void>()
    {
        return 0;
    }
    

    当foo<>(),默认情况下T将设置为void,将调用最后一个函数而不是其他函数,并返回0作为大小。