Перегрузка функций шаблонами - применение enable_if только при наличии альтернативной функции - PullRequest
1 голос
/ 22 сентября 2019

Мне удалось перегрузить оператор вставки для std::ostream в зависимости от ранга объекта.Я хотел бы расширить приведенный ниже пример.

Когда включено A_new.h, оно включает A.h ... в этом случае я проверяю ранг объекта и звоню f_alterantive или f_old.Работает, как и ожидалось:)

Проблема возникает, когда A.h включен напрямую, тогда существует только один экземпляр f() - f_old.

Если существует только один экземпляр f() включается напрямую через A.h, тогда оно должно быть по умолчанию для всех объектов ... (не только для rank > 1, но и для всех остальных) и условие ниже не имеет смысла.

typename std::enable_if <(std::rank<T>::value > 1), int>::type = 0 >

Я знаю, что мне нужно указать условие, которое проверяет, существует ли другой f(): что-то вроде:

//goal:    typename std::enable_if <((f_alternative_exist == false) || (std::rank<T>::value > 1 && f_alternative_exist == true) ), int>::type = 0 >

Я нашел аналогичный вопрос , ноЯ до сих пор не уверен, как это сделать с std::enable_if

#include <iostream>
#include <type_traits>
#include <sstream>

class Foo {
};
    //--- alternative header A_new.h
    //#include A.h
    template< class T,
             typename std::enable_if<(std::rank<T>::value == 1), int>::type = 0 >
    void f(std::ostream& os, const T& value)
    //f_alternative 
    {
        os << "alternative function\n";
        os << "rank == 1" << std::endl;
    }
    //----

    //---- old header A.h
    template < class T,
               typename std::enable_if <(std::rank<T>::value > 1), int>::type = 0 >
    //goal:    typename std::enable_if <((f_alternative_exist == false) || (std::rank<T>::value > 1 && f_alternative_exist == true) ), int>::type = 0 >
    void f(std::ostream& os, const T& value)
    //f_old
    {
        os << "old function\n";
        os << "rank > 1" << std::endl;
    }

    template <class T>
    std::ostream& operator<<(std::ostream& os, const T& foo)
    {
        f<T>(os, foo);
        return os;
    }
    //-----

int main()
{
    Foo foo1[5];
    Foo foo2[5][5];

    std::cout << foo1; 
    std::cout << foo2;

    return 0;
}

https://coliru.stacked -crooked.com / a / 7f7ef7bda1805a36

Не могли бы вы сказать мне, какможно ли указать std::enable_if для работы также, когда f() не перегружен и когда он должен работать во всех случаях?

1 Ответ

1 голос
/ 22 сентября 2019

Возможен f_alternative_exist следующий

template <typename T>
std::false_type f_alternative_exist_f (std::ostream &, T const &, long);

template <typename T>
auto f_alternative_exist_f (std::ostream & os, T const & t, int)
   -> decltype( f(os, t), std::true_type{} );

template <typename T>
using f_alternative_exist
   = decltype(f_alternative_exist_f(std::declval<std::ostream &>(),
                                    std::declval<T>(), 0));

template <typename T>
static constexpr bool f_alternative_exist_v
   = f_alternative_exist<T>::value;

Старая версия становится

template <typename T, 
          std::enable_if_t<(std::rank<T>::value > 1)
                        || (false == f_alternative_exist_v<T>), int> = 0 >
void f (std::ostream & os, T const &)
 {
   os << "old function\n";
   os << "rank > 1" << std::endl;
 }

Ниже приведен пример полной компиляции C ++ 14

#include <iostream>
#include <type_traits>
#include <sstream>

class Foo
 { };

template <typename T>
std::false_type f_alternative_exist_f (std::ostream &, T const &, long);

template <typename T>
auto f_alternative_exist_f (std::ostream & os, T const & t, int)
   -> decltype( f(os, t), std::true_type{} );

template <typename T>
using f_alternative_exist
   = decltype(f_alternative_exist_f(std::declval<std::ostream &>(),
                                    std::declval<T>(), 0));

template <typename T>
static constexpr bool f_alternative_exist_v
   = f_alternative_exist<T>::value;

#if 0 // enable/disable
template <typename T,
          std::enable_if_t<std::rank<T>::value == 1, int> = 0 >
void f (std::ostream & os, T const &)
 {
   os << "alternative function\n";
   os << "rank == 1" << std::endl;
 }
#endif

template <typename T, 
          std::enable_if_t<(std::rank<T>::value > 1)
                        || (false == f_alternative_exist_v<T>), int> = 0 >
void f (std::ostream & os, T const &)
 {
   os << "old function\n";
   os << "rank > 1" << std::endl;
 }

template <typename T>
std::ostream& operator<<(std::ostream& os, const T& foo)
 {
   f<T>(os, foo);
   return os;
 }

int main ()
 {
   Foo foo1[5];
   Foo foo2[5][5];

   std::cout << foo1; 
   std::cout << foo2;
 }
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...