c ++: существует ли что-то вроде «условного повышения / стандартного ввода», которое генерирует значение (а не тип) во время компиляции? - PullRequest
3 голосов
/ 19 сентября 2011

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

        //if B is true, m_value = TRUEVAL, else FALSEVAL, T is the value type
        template<bool B, class T, T TRUEVAL, T FALSEVAL>
        struct ConditionalValue
        {
            typedef T Type;

            Type m_value;

            ConditionalValue():
            m_value(TRUEVAL)
            {}
        };

        template<class T, T TRUEVAL, T FALSEVAL>
        struct ConditionalValue<false, T, TRUEVAL, FALSEVAL>
        {
            typedef T Type;

            Type m_value;

            ConditionalValue():
            m_value(FALSEVAL)
            {}
        };

Тогда вы можете просто сделать что-то вроде этого:

template<class T>
void loadPixels(uint32 _w, uint32 _h, T * _pixels)
{
    PixelDataType::Type pixelType = PixelDataType::Auto; //enum I want to set

    ConditionalValue<boost::is_same<T, uint8>::value, PixelDataType::Type, PixelDataType::UInt8, PixelDataType::Auto> checker;
    pixelType = checker.m_value;

   ConditionalValue<boost::is_same<T, uint16>::value, PixelDataType::Type, PixelDataType::UInt16, PixelDataType::Auto> checker2;
   pixelType = checker2.m_value;

   ...

}

Я знаю, что этот пример не имеет особого смысла, но я использую этот код для установки значения enum во время компиляции. Так вот мой вопрос: Есть ли что-то подобное в чертах типа std / boost allready? При просмотре ссылки я нашел только условное , которое делает почти то, что я хочу, но генерирует только тип, а не значение.

EDIT:

Обновленный пример.

Edit2:

Я только что понял, что boost :: is_same :: value - это все, что мне нужно для решения моей проблемы. Что касается ответа на вопрос: похоже, что в std / boost ничего не включено по веской причине, как указано титон

EDIT3: Если вы все еще ищете решение для создания значения во время компиляции, вы можете использовать мой код, который работает. Если вы ищете что-то очень близкое к boost / stl Kerrek's или Nawaz , то, кажется, также являются правильными решениями. Если вы ищете решение, которое присваивает правильное перечисление во время компиляции Luc Touraille подход кажется интересным, хотя я решил, что это излишне для моей ситуации!

Ответы [ 5 ]

5 голосов
/ 19 сентября 2011

Сочетание std::conditional и std::integral_constant может работать в некоторых ситуациях:

template <bool B, typename T, T trueval, T falseval>
struct conditional_val : std::conditional<B,
       std::integral_constant<T, trueval>,
       std::integral_constant<T, falseval>>::type
{ };

Теперь используйте:

const int q = conditional_val<B, int, 12, -8>::value;

Эквивалентное:

const int q = B ? 12 : -8;
2 голосов
/ 19 сентября 2011

Я думаю, что это простой ответ: потому что оператор?: Может выбирать значения достаточно хорошо. Типы сложнее выбрать, поэтому для этого существуют буст-конструкции. Для патологических случаев магия boost :: mpl, предложенная Люком, подойдет, но это должно быть довольно редко.

2 голосов
/ 19 сентября 2011

Boost.MPL содержит набор классов для манипулирования типами данных во время компиляции, а также некоторые арифметические операции.Эти классы переносят значение в тип, например, целое число 4 может быть представлено типом mpl::int_<4>.

. Вы можете использовать их в условных выражениях во время компиляции:

typedef typename 
    mpl::if_< 
        boost::is_same< T, uint8 >, 
        mpl::int_< 42 >, 
        mpl::int_< 187 >
    >::type result;

int i = result::value;

MPL также предоставляет универсальную встроенную оболочку , которую вы можете использовать со своими перечислениями:

template<class T>
void loadPixels(uint32 _w, uint32 _h, T * _pixels)
{
    PixelDataType::Type pixelType = PixelDataType::Auto; //enum I want to set

    typedef typename mpl::if_<
        boost::is_same<T, uint8>, 
        mpl::integral_c<PixelDataType::Type, PixelDataType::UInt8>,
        mpl::integral_c<PixelDataType::Type, PixelDataType::Auto>
    >::type checker;

    pixelType = checker::value;

    typedef typename mpl::if_<
        boost::is_same<T, uint16>, 
        mpl::integral_c<PixelDataType::Type, PixelDataType::UInt16>,
        mpl::integral_c<PixelDataType::Type, PixelDataType::Auto>
    >::type checker2;

    pixelType = checker2::value;

    ...
}

Если у вас много подобных сопоставлений, вы можете рассмотреть возможность использования смешанной компиляцииструктура данных времени / времени выполнения, такая как fusion :: map , но это, вероятно, немного излишне:):

typedef fusion::map<
    fusion::pair<uint8, PixelDataType::Type>,
    fusion::pair<uint16, PixelDataType::Type> >
map_type;

map_type pixelTypesMap(
    make_pair<uint8>(PixelDataType::UInt8),
    make_pair<uint16>(PixelDataType::UInt16));

...

template<class T>
void loadPixels(uint32 _w, uint32 _h, T * _pixels)
{
    // need special handling if T is not in the map
    PixelDataType::Type pixelType = fusion::at_key<T>(pixelTypesMap);

    ...
}
0 голосов
/ 19 мая 2014

Я сталкивался со случаем, когда мне нужно было делать именно то, что делает ? (сравнивать значения, возвращать значения), но используя специализацию шаблонов (зачем вам это нужно?) Просто: оценка времени компиляции ? может привести к предупреждения о недоступном коде)

Итак, самое стандартное решение, которое подходит как для вашего первоначального вопроса, так и для моего imho:

std::conditional<myval, 
                 std::integral_constant<T, val>, 
                 std::integral_constant<T, val>
                >::type::value;

Теперь просто замените «myval» на std::is_same, и у вас есть решение для вашего случая (сравните типы, возвращаемые значения), в то время как выше - решение для моего случая (сравните значения, возвращаемые значения <=> ?)

0 голосов
/ 19 сентября 2011

Вы можете написать сами:

namespace extend 
{
  template<bool B, class T, T X, T Y>  
  struct conditional
  {
       static const T value = X;
  };
  template<class T, T X, T Y>  
  struct conditional<false,T,X,Y>
  {
       static const T value = Y;
  };
}

//test
assert(conditional<std::is_same<int,int>::value, int, 10, 20>::value == 10);
assert(conditional<std::is_same<int,char>::value, int, 10, 20>::value == 20);
...