c ++ std :: enable_if .... еще? - PullRequest
       40

c ++ std :: enable_if .... еще?

5 голосов
/ 17 февраля 2020
#include <stdio.h>
#include <type_traits>

void print()
{
    printf("cheers from print !\n");
}

class A 
{
  public:
  void print()
  {
      printf("cheers from A !");
  }
};


template<typename Function>
typename std::enable_if< std::is_function< 
                                typename std::remove_pointer<Function>::type >::value,
                                void >::type 
run(Function f)
{
    f();
}


template<typename T>
typename std::enable_if< !std::is_function< 
                                typename std::remove_pointer<T>::type >::value,
                                void >::type 
run(T& t)
{
    t.print();
}



int main()
{
    run(print);

    A a;
    run(a);

    return 0;
}

Приведенный выше код компилируется и печатается, как и ожидалось:

ура от печати! ура от A!

, что я бы хотел express: «если шаблон является функцией, тогда примените эту функцию, иначе ...». Или в другой формулировке: наличие версии функции для шаблонов функций и версии по умолчанию для не функциональных шаблонов.

так что эта часть кажется несколько избыточной и может быть «заменена» условием «else» :

template<typename T>
typename std::enable_if< !std::is_function< 
                                typename std::remove_pointer<T>::type >::value,
                                void >::type 
run(T& t)

будет ли это существовать?

Ответы [ 2 ]

6 голосов
/ 17 февраля 2020

То, что вы ищете, это constexpr, если . Это позволит вам написать код вроде

template<typename Obj>
void run(Obj o)
{
    if constexpr (std::is_function_v<std::remove_pointer_t<Obj>>)
        o();
    else
        o.print();
}

Live Example

Если у вас нет доступа к C ++ 17, но если у вас есть C ++ 14, вы можете по крайней мере сократить код, который вам нужно написать, используя шаблон переменной . Это выглядело бы как

template<typename T>
static constexpr bool is_function_v = std::is_function< typename std::remove_pointer<T>::type >::value;

template<typename Function>
typename std::enable_if< is_function_v<Function>, void>::type 
run(Function f)
{
    f();
}


template<typename T>
typename std::enable_if< !is_function_v<T>, void>::type 
run(T& t)
{
    t.print();
}

Живой пример

4 голосов
/ 17 февраля 2020

Вы можете использовать механизм отправки тегов, если вы ограничены использованием C ++ 11.

namespace detail
{
   template<typename Function>
   void run(std::true_type, Function& f)
   {
      f();
   }

   template<typename Object>
   void run(std::false_type, Object& o)
   {
      o.print();
   }

} // namespace detail

template<typename T>
void run(T& t)
{
   constexpr bool t_is_a_function = 
      std::is_function<typename std::remove_pointer<T>::type >::value;
   using tag = std::integral_constant<bool, t_is_a_function>;
   detail::run(tag{}, t);
}

Рабочий пример .

...