Вопрос

Я смотрел последние C9 Лекция и заметил что -то интересное ..

Во введении в Type_Traits Стефан использует следующий (как он говорит, надуман) пример:

template <typename T> void foo(T t, true_type)
{
    std::cout << t << " is integral";
}
template <typename T> void foo(T t, false_type)
{
    std::cout << t << " is not integral";
}

шаблон <typename T> void bar (t t) {foo (t, typename is_integral<T>::type()); }

Это кажется гораздо сложнее, чем:

template <typename T> void foo(T t)
{
    if(std::is_integral<T>::value)
        std::cout << "integral";
    else
        std::cout << "not integral";
}

Есть ли что -то не так с последним способом сделать это? Его путь лучше? Почему?

Спасибо.

Это было полезно?

Решение

Пример ниже должен проиллюстрировать разницу. Давайте добавим Struct x:

struct X
{
  X(int)
  {
  }
};

и изменить один Foo, как ниже:

template <typename T> void foo(T t, true_type)
{
    std::cout << t << " is integral";
    X x(t);
}
template <typename T> void foo(T t, false_type)
{
    std::cout << t << " is not integral";
}

Затем:

template <typename T> void bar(T t)
{
    foo(t, typename is_integral<T>::type());
}

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

Другой эквивалентный код:

template <typename T> void foo(T t)
{
    if(std::is_integral<T>::value)
    {
        std::cout << "integral";
        X x(t);
    }
    else
        std::cout << "not integral";
}

Часто не сможет компилировать, поскольку вы не сможете создавать экземпляры x для типов, кроме интегральных и в конечном итоге плавучих и пользовательских классов, которые имеют оператор int () (Operator short () или оператор Long () не подойдут).

Другие советы

В основном First Option использует знания о «интегральности» типа во время компиляции и второй вариант-перемещает эти знания к времени выполнения.

Это означает, что мы можем использовать для интегральных типов кода, который не поддается компиляции для неинтегральных типов.

Для такого маленького, надуманного примера нет особого преимущества для этого первого пути. Преимущество приходит, когда у вас есть более сложные ситуации. По сути, это аналогично использованию полиморфизма на основе наследования или операторов IF/Switch в объектно-ориентированном программировании. Более сложное решение позволяет вам большую гибкость; Вы можете легко добавить типы без изменения существующего кода.

Если вы знаете все типы, которые вам когда -либо понадобятся (например, вы используете логический, в качестве примера), то более простое решение может быть лучше. Но если у вас нет фиксированных требований (и когда требования когда -либо исправлены?), Более сложное, но более гибкое решение, вероятно, будет проще в долгосрочной перспективе.

Используя первый подход, вы можете реализовать статический дипттч без с использованиемif/else или же switch.

template <typename T> 
void Dispatch(T t)
{
    //Call foo(T, true_type) or foo(T, false_type)
    //depending upon the *type* of second parameter.
    foo(t, typename is_integral<T>::type());
}

Используя второй подход, вы должны реализовать это, используя if/else или же switch блокировать,

template <typename T> 
void Dispatch(T t)
{
    //Call foo(T, true_type) or foo(T, false_type)
    //depending upon the *value* of value.
    if(std::is_integral<T>::value)
        foo(t, true_type());
    else
        foo(t, false_type());
}

Но если вы хотите реализовать свой Dispatch() функция без использования if/else, и в то же время вы хотите использовать std::is_integral<T>::value, тогда вам нужно переписать свой foo() функция, как это,

template <bool b> 
void foo(T t)
{
    std::cout << t << " is integral";
}

template <> 
void foo<false>(T t)
{
    std::cout << t << " is not integral";
}

И ваш Dispatch() функция будет выглядеть как,

 template <typename T> 
 void Dispatch(T t)
 {
     //using std::is_integral<T>::value!
     const bool selector = (bool) std::is_integral<T>::value;
     foo<selector>(t);
 }
Лицензировано под: CC-BY-SA с атрибуция
Не связан с StackOverflow
scroll top