値またはコールバック関数の割り当て時のC ++オーバーロードテンプレート


8

次のようなことをしようとしています...

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

ここでSFINAEを使用する必要があることはわかっていますが、コールバックパラメーターと値パラメーターをどのように区別しますか?値をコールバックとして使用できないと想定しても安全です。

私が試したenable_ifis_function, result_ofinvoke_resultis_invocable、など、それのどれも右に動作しません。可能ですか?

回答:


9

SFINAEなしでそれを行うことができます:

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

またはより一般的な方法で:

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
constexprコンパイル時間が短縮されるため、SFINAEよりも優先
Dev Null

7

はいstd::is_invocable(C ++ 17以降)の助けを借りてSFINAEを適用できます。

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

住む


4

関数を引数としてとるオーバーロードは、次のように定義できます。

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

デモコード:

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

出力:

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

1
これは貧弱なソリューションです。あなたは関数ポインタだけを受け入れています。ラムダも「呼び出し可能クラス」も渡すことはできません。
Bktero
弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.