Modelo de sobrecarga C ++ na atribuição de valor ou função de retorno de chamada

8

Tentando fazer 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;
};

Sei que preciso usar o SFINAE aqui, mas como faço para distinguir um parâmetro de retorno de chamada de um parâmetro de valor? É seguro assumir que um valor não pode ser usado como retorno de chamada.

Eu tentei enable_ifcom is_function, result_of, invoke_result, is_invocable, e outros, mas nada disso funciona direito. Isso é possível?

Allen Ienus
fonte

Respostas:

9

Você pode fazer isso sem SFINAE:

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

ou de uma maneira mais 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);
}
Evg
fonte
2
prefere constexpro SFINAE por causa dos melhores tempos de compilação #
Dev Null
7

Sim, você pode aplicar o SFINAE com a ajuda 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(); }

VIVER

songyuanyao
fonte
4

A sobrecarga que assume uma função como argumento pode ser definida como:

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

Código demonstrativo:

#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);
}

Resultado:

In set(const U& u)
In set(R (*f)())
R Sahu
fonte
1
Esta é uma solução ruim. Você está aceitando apenas ponteiros de função. Você não pode passar lambdas nem "classes de chamada".
Bktero