所以这里的情况是:我有两个使用CRTP进行静态继承的类。基类具有调用变参模板的派生方法的run方法,以使参数灵活。现在派生类包含一个函数对象。派生类具有由基类调用的实现。可能看起来不必要,但在这段代码的完整版本中,运行的不仅仅是包含的函数。接下来有一个方法,将函数绑定到
CrtpBase :: Run
方法的所有变参参数和实例,从而将函数转换为bool(void)函数。这就是我遇到问题的地方。我尝试了两种不同的方法,使用lambda的版本已被注释掉。两种方法都不起作用。我的目标是让VoidFunction
绑定所有参数,以便我可以在没有参数的情况下随意执行该函数。我在这里做错了什么?#include <functional>
#include <utility>
template <typename D>
struct CrtpBase {
template <typename ... Args>
bool Run(Args&& ... args) const {
return static_cast<D&>(*this).Impl(std::forward<Args>(args) ...);
}
};
template <typename ... Args>
struct CrtpDerived : public CrtpBase<CrtpDerived<Args ...>> {
CrtpDerived(std::function<bool(Args ...)> function) : runable(std::move(function)) {}
bool Impl(Args&& ... args) const {
return this->runable(std::forward<Args>(args) ...);
}
std::function<bool(Args ...)> runable;
};
template <typename D, typename ... Args>
std::function<bool()> VoidFunction(CrtpBase<D> base, Args&& ... args) {
// return [&base, &args ...]()->bool{return CrtpBase<D>::template Run<Args ...>(base);};
return std::bind(CrtpBase<D>::template Run<Args ...>, base, std::forward<Args>(args) ...);
}
int main(int argc, char** argv) {
std::function<bool(int&)> fn = [](int& a)->bool{a /= 2; return (a % 2) == 1;};
CrtpDerived<int&> derived(fn);
int x = 7;
auto voided = VoidFunction(derived, x);
bool out = voided();
if ((x == 3) and (out == true)) {
return EXIT_SUCCESS;
} else {
return EXIT_FAILURE;
}
}
修订:
- 修正最终测试中的拼写错误,
(out == false)
改为(out == true)
const D&
。这很有道理。它可以编译通过。但是当它运行时,它会抛出一个std::bad_function_call实例,所以仍然存在问题。 - esdanolbase
被销毁,并在修复后的代码中将其更正为引用,但我还要指出发生在非引用基类变量中的对象切片。 - aschepler。而您正在将
CrtpDerived<int&> derived作为参数传递。会发生的是,将传递
derived的
CrtpBase<D>子对象的副本,而不是整个
derived对象(这就是“切片”)。稍后,尝试将该
base强制转换为
CrtpDerived<int&>将仅导致未定义行为,因为该
base不再是任何
CrtpDerived<int&>`的一部分。 - AnT stands with Russia