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_of, invoke_result, is_invocable等,但都不起作用。这是否可能?

3个回答

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

是的,您可以在C++17中使用std::is_invocable来应用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(); }

LIVE


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
这是一个不好的解决方案。你只接受函数指针,无法传递lambda表达式或“可调用类”。 - Bktero

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接