Plantilla de sobrecarga de C ++ al asignar valor o función de devolución de llamada


8

Tratando de hacer algo como ...

template <class T>
struct Wrapper
{
    template <class U>
    void set(const U& u) { myT = u; }

    template <class F>
    void set(F f) { myT = f(); }

    T myT;
};

Sé que necesito usar SFINAE aquí, pero ¿cómo puedo distinguir un parámetro de devolución de llamada de un parámetro de valor? Es seguro asumir que un valor no puede usarse como devolución de llamada.

He tratado enable_ifcon is_function, result_of, invoke_result, is_invocable, y otros, pero nada de esto funciona bien. ¿Es posible?

Respuestas:


9

Puedes hacerlo sin SFINAE:

template<class U>
void set(const U& u) { 
    if constexpr (std::is_invocable_v<U>)
        myT = u();
    else
        myT = u;
}

o de una manera más genérica:

template<class U>
void set(U&& u) { 
    if constexpr (std::is_invocable_v<U>)
        myT = std::forward<U>(u)();
    else
        myT = std::forward<U>(u);
}

2
prefiero constexpra SFINAE debido a mejores tiempos de compilación
Dev Null

7

Sí, puede aplicar SFINAE con la ayuda de std::is_invocable(desde C ++ 17).

template <class U>
std::enable_if_t<!std::is_invocable_v<U>> set(const U& u) { myT = u; }

template <class F>
std::enable_if_t<std::is_invocable_v<F>> set(F f) { myT = f(); }

EN VIVO


4

La sobrecarga que toma una función como argumento se puede definir como:

template <typename R>
   void set(R (*f)())
   {
      myT = f();
   }

Código demostrativo:

#include <iostream>

template <class T>
struct Wrapper
{
   template <class U>
      void set(const U& u)
      {
         std::cout << "In set(const U& u)\n";
         myT = u;
      }

   template <typename R>
      void set(R (*f)())
      {
         std::cout << "In set(R (*f)())\n";
         myT = f();
      }

   T myT;
};

short foo()
{
   return 2u;
}

int main()
{
   Wrapper<int> a;
   a.set(1u);
   a.set(foo);
}

Salida:

In set(const U& u)
In set(R (*f)())

1
Esta es una mala solución. Acepta solo punteros de función. No puede pasar lambdas ni "clases invocables".
Bktero
Al usar nuestro sitio, usted reconoce que ha leído y comprende nuestra Política de Cookies y Política de Privacidad.
Licensed under cc by-sa 3.0 with attribution required.