绑定到可变成员函数
Binding to a variadic member function
情况是这样的:我有两个 classes 通过 CRTP 进行静态继承。基础 class 有一个 运行 方法,该方法使用可变参数模板调用派生方法,因此参数很灵活。现在派生的 class 包含一个函数对象。派生 class 具有由基 class 调用的实现。这似乎是不必要的,但在这段代码的完整版本中,除了包含的函数之外,还有更多命令 运行。接下来有一个方法通过将所有可变参数和实例绑定到方法 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)
首先,从编译器的角度来看 CrtpBase<D>::template Run<Args ...>
是一个 nonsensical/incomplete 的标记组合。 C++ 中没有这样的表达式语法。这看起来像是试图形成指向成员的指针,但这需要显式应用 &
operator
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) ...);
将隐含的 this
参数绑定到函数参数 base
。这是行不通的,因为一旦 VoidFunction
退出(或调用表达式结束),base
就会被销毁。正如@aschepler 在评论中正确指出的那样,将 base
作为 CrtpBase<D>
值传递给原始 CrtpDerived<int&>
对象。通过引用传递它,然后使用 &base
作为 std::bind
.
的参数
第四,std::bind
will not bind "by reference"和std::forward
不会帮你解决这个问题。这意味着您的 lambda fn
中的 a
不会绑定到 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
。
情况是这样的:我有两个 classes 通过 CRTP 进行静态继承。基础 class 有一个 运行 方法,该方法使用可变参数模板调用派生方法,因此参数很灵活。现在派生的 class 包含一个函数对象。派生 class 具有由基 class 调用的实现。这似乎是不必要的,但在这段代码的完整版本中,除了包含的函数之外,还有更多命令 运行。接下来有一个方法通过将所有可变参数和实例绑定到方法 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)
首先,从编译器的角度来看 CrtpBase<D>::template Run<Args ...>
是一个 nonsensical/incomplete 的标记组合。 C++ 中没有这样的表达式语法。这看起来像是试图形成指向成员的指针,但这需要显式应用 &
operator
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) ...);
将隐含的 ,this
参数绑定到函数参数 base
。这是行不通的,因为一旦 VoidFunction
退出(或调用表达式结束)base
就会被销毁。正如@aschepler 在评论中正确指出的那样,将 base
作为 CrtpBase<D>
值传递给原始 CrtpDerived<int&>
对象。通过引用传递它,然后使用 &base
作为 std::bind
.
第四,std::bind
will not bind "by reference"和std::forward
不会帮你解决这个问题。这意味着您的 lambda fn
中的 a
不会绑定到 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
。