C ++ - Überladungsvorlage beim Zuweisen von Wert oder Rückruffunktion

8

Der Versuch, so etwas wie ...

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

Ich weiß, dass ich hier SFINAE verwenden muss, aber wie unterscheide ich einen Rückrufparameter von einem Wertparameter? Es ist sicher anzunehmen, dass ein Wert nicht als Rückruf verwendet werden kann.

Ich habe versucht , enable_ifmit is_function, result_of, invoke_result, is_invocable, und andere, aber nichts davon richtig funktioniert. Ist es überhaupt möglich?

Allen Ienus
quelle

Antworten:

9

Sie können es ohne SFINAE tun:

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

oder allgemeiner:

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
quelle
2
constexprwegen besserer Kompilierungszeiten SFINAE vorziehen
Dev Null
7

Ja, Sie können SFINAE mit Hilfe von std::is_invocable(seit C ++ 17) anwenden .

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

LEBEN

songyuanyao
quelle
4

Die Überladung, die eine Funktion als Argument annimmt, kann wie folgt definiert werden:

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

Demonstrativer Code:

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

Ausgabe:

In set(const U& u)
In set(R (*f)())
R Sahu
quelle
1
Dies ist eine schlechte Lösung. Sie akzeptieren nur Funktionszeiger. Sie können weder Lambdas noch "aufrufbare Klassen" übergeben.
Bktero