2015-05-15 3 views
3

Я все чаще нахожу ограниченные перечисления, громоздкие в использовании. Я пытаюсь написать набор функциональных перегрузок, включая шаблон для контекстных перечислений, который устанавливает/инициализирует значение по ссылке - что-то вроде этого:Изменение охваченного перечисления по ссылке

void set_value(int& val); 
void set_value(double& val); 
template <typename ENUM> set_value(ENUM& val); 

Однако, я не совсем понимаю, как написать шаблонный версия set_value без введения нескольких временных значений:

template <typename ENUM> 
set_value(ENUM& val) 
{ 
    std::underlying_type_t<ENUM> raw_val; 
    set_value(raw_val); // Calls the appropriate "primitive" overload 
    val = static_cast<ENUM>(raw_val); 
} 

Я считаю, что static_cast вводит второе временное значение в дополнение к raw_val. Я полагаю, что возможно, что один или оба из них могут быть оптимизированы компилятором, и в любом случае это не должно иметь особого значения с точки зрения производительности, поскольку звонок set_value также генерирует временные значения (при условии, что он не встроен), но это все еще кажется неэлегантным. Что бы я как сделать бы что-то вроде этого:

template <typename ENUM> 
set_value(ENUM& val) 
{ 
    set_value(static_cast<std::underlying_type_t<ENUM>&>(val)); 
} 

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

Я мог бы использовать reinterpret_cast, который, по некоторым предварительным проверкам, кажется, работает (и я не могу думать о какой-либо причине, почему это не сработает), но на C++ это кажется неодобрительным.

Существует ли «стандартный» способ сделать это?

+0

Переименование (с областью действия или нет) является целым числом, а целые числа практически бесплатны. Не нужно беспокоиться о «временных». Доверяйте оптимизатору. –

+0

@MattiVirkkunen Я попытался уточнить в вопросе, что это не касается оптимизации, так как я не ожидаю разницы в производительности. Я просто хочу более элегантный код, потому что важна выразительность. –

+0

... также вы имели в виду присвоение val raw_val? –

ответ

0

я мог бы использовать reinterpret_cast, что, начиная с некоторого предварительного тестирования, кажется, работает (и я не могу думать о какой-либо причине, почему она не будет работать), но это, кажется, неодобрением в C++.

Действительно, это неопределенное поведение путем нарушения правила строгого сглаживания.

Устранение одной инструкции mov (или иного, более или менее точного копирования данных реестра) является преждевременной микро-оптимизацией. Возможно, компилятор сможет позаботиться об этом.

Если производительность действительно важна, выполните процесс оптимизации: профиль, разобрать, понять интерпретацию компилятора и работать вместе с ним в рамках определенных правил.

С первого взгляда у вас (и компилятора) может быть проще время с функциями, такими как T get_value() вместо void set_value(T). Поток данных и инициализация имеют больше смысла, хотя вывод типа теряется. Вы можете восстановить вычет через теги, если это действительно важно.

+0

Как отмечено в вопросе и в предыдущем комментарии, меня не интересует производительность; Я просто нахожу введение 'raw_value' inelegant. –

+1

@KyleStrand Как отмечено в этом ответе, вместо этого используйте 'get_value'. «Исходные параметры» должны быть последним средством. – Potatoswatter