如何处理空参数包的情况

时间:2015-03-13 07:08:55

标签: c++ templates c++11 variadic-templates

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

// 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<>();

请注意,我不想修改调用foo的方式,尖括号必须保持在那里。我希望修改getSize,因为我在foo以外的几个函数中使用它。修改foo作为最后的手段。

3 个答案:

答案 0 :(得分:3)

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

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;
}

接下来,打包的东西会将类型包扩展为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的显式类型。

答案 1 :(得分:3)

解决这个问题的另一种方法是使用一些像

这样的小结构
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...>的特化,并将Head中的类型大小添加到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 :(得分:1)

如果您只想编辑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&lt;&gt;()时,默认情况下T将被设置为void,并且将调用最后一个函数而不是其他函数,它将返回0作为大小。