这是这种情况:我有两个通过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)
答案 0 :(得分:1)
首先,从编译器的角度来看,CrtpBase<D>::template Run<Args ...>
是令牌的荒谬/不完整的组合。 C ++中没有这样的表达语法。这看起来像是尝试形成一个指向成员的指针,但这需要显式应用&
运算符
return std::bind(&CrtpBase<D>::template Run<Args ...>, base, std::forward<Args> (args) ...);
第二,这个演员
static_cast<D&>(*this)
将尝试放弃常数。 static_cast
不允许这样做。
第三,您的
std::bind(&CrtpBase<D>::template Run<Args ...>, base, std::forward<Args> (args) ...);
将隐含的。正如@aschepler在通过this
参数绑定到功能参数base
。这将行不通,因为base
会在VoidFunction
退出时(或在调用表达式结束时)被销毁。base
值传递CrtpBase<D>
的注释中正确标注的那样,将原始CrtpDerived<int&>
对象切成薄片。通过引用将其传递,然后使用&base
作为std::bind
的参数。
第四,std::bind
will not bind "by reference"和std::forward
对此无济于事。这意味着您的a
内部的fn
将不会绑定到x
。使用std::ref
来解决该限制。
#include <functional>
#include <utility>
template <typename D>
struct CrtpBase {
template <typename ... Args>
bool Run(Args&& ... args) const {
return static_cast<const 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 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, std::ref(x));
bool out = voided();
if ((x == 3) && (out == false)) {
return EXIT_SUCCESS;
} else {
return EXIT_FAILURE;
}
}
最后一件事:我不明白您为什么期望您的out
最终成为false
。