【问题标题】:Polymorphic signature of function as template argument (using lambdas)函数的多态签名作为模板参数(使用 lambdas)
【发布时间】:2013-01-06 17:20:07
【问题描述】:

我努力了几个小时,但没有成功。

我有一个模板类自旋锁:

template<typename T> class spinlock {
  // ...
  volatile T *shared_memory;
};

我正在尝试创建这样的东西:

  // inside spinlock class
  template<typename F, typename... Ars>
  std::result_of(F(Args...))
  exec(F fun, Args&&... args) {
    // locks the memory and then executes fun(args...)
  };

但我正在尝试使用多态函数以便我可以做到这一点:

spinlock<int> spin;

int a = spin.exec([]() {
  return 10;
});

int b = spin.exec([](int x) {
  return x;
}, 10); // argument here, passed as x

// If the signature matches the given arguments to exec() plus
// the shared variable, call it
int c = spin.exec([](volatile int &shared) {
  return shared;
}); // no extra arguments, shared becomes the
    // variable inside the spinlock class, I need to make
    // a function call that matches this as well

// Same thing, matching the signature
int d = spin.exec([](volatile int &shared, int x) {
  return shared + x;
}, 10); // extra argument, passed as x... should match too

// Here, there would be an error
int d = spin.exec([](volatile int &shared, int x) {
  return shared + x;
}); // since no extra argument was given 

基本上,我正在尝试创建一个接受F(Args...)F(volatile T &amp;, Args...) 作为参数的exec 函数。

但我无法自动检测类型。 我怎样才能做到这一点?

【问题讨论】:

    标签: c++ templates c++11 lambda polymorphism


    【解决方案1】:

    首先,这个签名不会编译:

    // inside spinlock class
    template<typename F, typename... Ars>
    std::result_of(F(Args...))
    exec(F fun, Args&&... args) {
      // locks the memory and then executes fun(args...)
    };
    

    返回类型需要是

    typename std::result_of<F(Args...)>::type
    

    如果您的编译器实现了N3436,那么当fun(args...) 不是有效表达式时,此函数将不会参与重载解析,但在C++11 中不需要并且许多编译器尚未实现。您将需要实现自己的 SFINAE 检查以防止 result_offun(args...) 无效时出错,或者在没有 result_of 的情况下重写它

    template<typename F, typename... Args>
    auto
    exec(F fun, Args&&... args) -> decltype(fun(std::forward<Args>(args)...))
    {
      // locks the memory and then executes fun(args...)
    }
    

    然后可以为需要传入额外参数的函数重载:

    template<typename F, typename... Args>
    auto
    exec(F fun, Args&&... args) -> decltype(fun(*this->shared_memory, std::forward<Args>(args)...))
    {
      // locks the memory and then executes fun(*shared_memory, args...)
    }
    

    fun(std::forward&lt;Args&gt;(args)...) 无效时,第一个重载将不参与重载决议。当fun(*this-&gt;shared_memory, std::forward&lt;Args&gt;(args)...) 无效时,第二个重载将不参与重载决议。如果两者都无效,则调用将是格式错误的,如果两者都有效,则调用将是模棱两可的。

    【讨论】:

    • 是的,对不起,typename std::result_of&lt;F(Args...)&gt;::type 实际上是我的意思(我写得有点快)。但是...我已经测试了您的 SFINAE(我知道它是什么,但从未尝试过使用它)...效果很好!非常感谢! =D
    • 如果 T 不是无效的,您的两个签名都有效;但是如果 T(来自类)是无效的,我应该怎么做才能防止对 void 的引用? :(
    • 直到我意识到你想传递volatile T&amp;,但spinlock::shared_memory 成员是volatile T*,我才理解你的问题,所以我编辑了我的答案以使用*this-&gt;shared_memory .. . 但是如果Tvoid 显然这不起作用,无论如何你都不能声明一个函数来接受volatile void&amp; 所以这应该不是问题
    • 实际上,我使用的是volatile ptrdiff_t *shared_memory...而不是*this-&gt;shared_memory,我尝试了*((volatile T *)shared_memory),这应该是正确的,但后来spinlock.h:183:57: internal compiler error: Segmentation fault: 11...所以我解决了我的问题模板专业化的问题。非常感谢您的帮助,先生! =D
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多