2013-03-23 2 views
13

Я пишу псевдоним шаблона продвижения, подобный boost :: promotion, но для C++ 11. Целью этого является избежание предупреждений при извлечении аргументов из функций varidic. напримерХарактеристика типа C++ 11 для дифференциации класса enum и регулярного перечисления

template <typename T> 
std::vector<T> MakeArgVectorV(int aArgCount, va_list aArgList) 
{ 
    std::vector<T> args; 
    while (aArgCount > 0) 
    { 
     args.push_back(static_cast<T>(va_arg(aArgList, Promote<T>))); 
     --aArgCount; 
    } 
    return args; 
} 

Продвижения шаблона псевдонима способствует типу следующего продвижения аргумента по умолчанию для переменных числа аргументов: 1) Целого число, которое меньше ИНТ назначен Int 2) Поплавок способствуют двойной

Моя проблема в том, что стандартное перечисление C++ может быть продвинуто, но класс enum C++ 11 не продвигается (компилятор не генерирует предупреждение). Я хочу, чтобы Promote работал с регулярным перечислением, но игнорировал класс enum C++ 11.

Как я могу объяснить разницу между классом enum и перечислением в моем псевдониме шаблона Promote?

+1

Настоящая проблема заключается в том, что вы используете 'va_arg' вместо' std :: initializer_list' и/или вариационных шаблонов. – Fanael

+0

Спасибо за отзыв, но у меня есть va_list, потому что я работаю с C-интерфейсом. – Sam

+0

@Sam: Я отвечаю, решая вашу проблему? –

ответ

21

Вот возможное решение:

#include <type_traits> 

template<typename E> 
using is_scoped_enum = std::integral_constant< 
    bool, 
    std::is_enum<E>::value && !std::is_convertible<E, int>::value>; 

Решение использует разницу в поведении между областью действия и незаданные перечислениями, указанными в пункте 7.2/9 C++ 11 стандарта на:

значение перечислителя или объект неперечисленного типа перечисления преобразуется в целое число путем цельной рекламы (4.5). [...] Обратите внимание, что это неявное преобразование enum to int не предоставляется для перечисления с областью. [...]

Вот демонстрация того, как вы будете использовать его:

А вот live example.

БЛАГОДАРНОСТЬ:

Благодарности к Daniel Frey за указание на то, что мой предыдущий подход будет работать только до тех пор, пока не определяется пользователем перегрузка operator +.

+3

+1, но есть одна пещера: она работает только до тех пор, пока автор некоторого класса enum 'E' ** не определил свой собственный' operator + (int, E) '. Исправьте его, добавив 'void dummy (int)' и используйте 'decltype (dummy (std :: declval ()))'. –

+1

@ DanielFrey: Хорошая точка. Фактически, я мог бы использовать другой оператор, например '^', чтобы сделать менее вероятным вмешательство в пользовательскую перегрузку оператора –

+1

@AndyProwl: или вызвать функцию, которая принимает значение 'int'. – Fanael

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

  • Нет связанных вопросов^_^