2015-03-13 3 views
2

У меня есть следующий код, который я использую для получения размера всех примитивных типов в пакете (я обрабатываю поплавки и удваивает особым образом), но моя программа не скомпилируется, когда пакет пуст.Как обрабатывать случай с пустым пакетом параметров

// 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 в качестве последнего средства.

ответ

2

Другой подход для решения этой проблемы было бы использовать пару маленьких структур, как

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> это приводит к

который затем

sizeof(int) + SIZEOF_DOUBLE + sizeof(char) + 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 необходим для обработки пустого пакета случая.

+0

Вы даже можете использовать 'std :: accumulate'. – Jarod42

+0

Красота рекурсии шаблонов исчезла, да. На самом деле, есть ли какие-либо преимущества в итерации с инициализационным списком по моему рекурсивному подходу к шаблону, кроме того, что он исправляет проблему, которую я имею? –

+0

@FlyingHat Это ИМО чище и понятнее. И проще в компиляторе, потому что он должен создавать меньше шаблонов. –

1

Если вы хотите, чтобы изменить функцию GETSIZE затем инициализировать шаблон первого свое T для аннулирования и добавления дополнительной функции шаблона для типа 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 будет установлен аннулирует по умолчанию, и эта последняя функция будет вызываться вместо других, и он будет возвращать 0, как размер.

Смежные вопросы