- html - 出于某种原因,IE8 对我的 Sass 文件中继承的 html5 CSS 不友好?
- JMeter 在响应断言中使用 span 标签的问题
- html - 在 :hover and :active? 上具有不同效果的 CSS 动画
- html - 相对于居中的 html 内容固定的 CSS 重复背景?
我在使用虚函数指针作为模板参数时遇到问题。问题似乎是编译器不会查找基类中的所有函数,或者无法将它们视为派生类的函数。
struct B1
{
virtual void b1() = 0;
virtual ~B1() = default;
};
struct B2
{
virtual void b2() = 0;
virtual ~B2() = default;
};
struct D1
: virtual public B1
{
void b1() override {}
};
struct D12
: virtual public D1
, virtual public B2
{
void b2() override {}
};
帮助类为给定实例执行一系列成员函数。
template<
typename T,
void(T::*...Fs)()>
struct Executor
{
static
void
execute(
T & t)
{}
};
template<
typename T,
void(T::*F)(),
void(T::*...Fs)()>
struct Executor<
T, F, Fs...>
{
static
void
execute(
T & t)
{
(t.*F)();
Executor<T, Fs...>::execute(t);
}
};
按给定顺序灵活执行函数的实际类
template<
typename T,
void(T::*...Fs)()>
struct FlexBind
{
std::unique_ptr<T> t;
void b()
{
Executor<T, Fs...>::execute(*t);
}
};
我的用例是我喜欢静态定义函数的调用顺序(编译时),但调用这些函数的对象实例是动态定义的(运行时)。
int main()
{
FlexBind<D12, D12::b1, D12::b2> FB1;//compile error
FlexBind<D12, D12::b2, D12::b1> FB2;
FB1.t.reset(new D12());
FB1.b();
FB2.t.reset(new D12());
FB2.b();
return 0;
}
我得到的错误是:
error: '&D1::b1' is not a valid template argument for type
'void (D12::*)()' because it is of type 'void (D1::*)()'
编译器无法匹配void (D12::*)()
和void (D1::*)()
如果我将函数 b1
添加到 D12
调用 D1::b1
一切都会编译并运行。
struct D12
: virtual public D1
, virtual public B2
{
void b1() override {D1::b1();}//would solve the problem, but is not feasible
void b2() override {}
};
不幸的是,在我的情况下,我无法更改类 D12
,是否有另一种可能让它运行?
我认为编译器知道继承层次结构,所以他应该知道哪些函数在哪个继承级别是已知的/可访问的。但可能我遗漏了一些它不起作用的原因?
最佳答案
不要使用成员函数指针,或者获取完全正确的类型(无转换)。
真的,与成员函数指针分离。存储 T*
的元组在不使用 std::function
的情况下使用函数对象(如果您关心一个或几个字节,则通过私有(private)继承(启用空基优化)) .
所以
template<class T, class...Fs>
我们创建 std::tuple<Fs...>
.我们通过遍历元组来执行(有很多关于这个的堆栈溢出问题,谷歌可以找到它们)。
我们可以用lambdas来描述调用成员函数,或者写一个template<class U, void(U::*mem)()>
如果您不喜欢必须实际传递无状态对象,请使用无状态助手。
这里有一些 C++14 助手:
template<class=void,std::size_t...Is>
auto indexer( std::index_sequence<Is...> ) {
return [](auto&&f)->decltype(auto) {
return decltype(f)(f)( std::integral_constant<std::size_t, Is>{}... );
};
}
// takes a number N
// returns a function object that, when passed a function object f
// passes it compile-time values from 0 to N-1 inclusive.
template<std::size_t N>
auto indexer() {
return indexer( std::make_index_sequence<N>{} );
}
// takes a function object f
// returns a function object that takes any number of arguments
// and invokes `f` on each of them
template<class F>
auto for_each_arg(F&& f) {
return [f = std::forward<F>(f)](auto&&...args)->void {
// this is a bit insane. We want to expand our parameter pack
// args... in a way that we do it from left to right. As it happens,
// creating a C-style array is one of the legal ways to do this.
// So we create an anonymous C-style array, and discard it immediately
// The void stuff is a mixture of suppressing warnings and
// ensuring that if someone has a hostile `operator,` it doesn't cause
// any issues
// the result of this expression is an array of `int` full of `0`,
// plus the function `f` invokes on each of the `args...` in order:
using discard=int[];
(void)discard{0,(void(
f( decltype(args)(args) )
),0)...};
};
};
给定一个元组 bob
lambdas,我们可以在某个指针上调用它们 p
像这样:
// the pack 0 to N-1, where N is the size of bob:
auto index = indexer<std::tuple_size<decltype(bob)>{}>();
// From a compile time `i`, do what we want:
auto invoker = [&](auto i) {
std::get<i>(bob)(p);
};
// For each compile time integer from 0 to N-1,
// call invoker:
index(for_each_arg(invoker));
所有这些在 C++17 中变得更加容易。
上面的代码充满了微优化,其中一些使其更难理解。如果你想了解更多,请直接在这个主题上找到一个 SO 问题,或者如果你找不到一个问题。
上面的一些是C++14。在 C++11 中,我们必须手动扩展其中一些 lambda。
例如,indexer
变成:
template<std::size_t...Is>
struct indexer_t {
template<class F>
auto operator()( F&& f ) const
-> decltype(std::forward<F>(f)( std::integral_constant<std::size_t, Is>{}... ))
{
return std::forward<F>(f)( std::integral_constant<std::size_t, Is>{}... );
}
};
template<class=void,std::size_t...Is>
indexer_t<Is...> indexer( std::index_sequence<Is...> )
{ return {}; }
template<std::size_t N>
auto indexer()
-> decltype( indexer(std::make_index_sequence<N>{}) ) )
{ return {}; }
或类似的东西。
一些名义上的 C++14 编译器可能也需要上述帮助(例如 MSVC2015),因为它们不允许您从 lambda 中的封闭上下文扩展参数包。
Live example #1和 Live example #2 .我用 std::array
因为它类似于元组(支持 get 和元素计数特征),但 3 个元素的输入更少。
关于c++ - 如何使用来自不同继承层次级别的多个虚函数指针作为模板参数?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/40575060/
我正在尝试将多个水平链接的 Button 和 TextView 垂直链接为 View 集,但仍保持平面 View 层次结构。这是我的初始布局和代码:
到目前为止,我已经在Google BigQuery上训练了几种模型,目前我需要查看模型的外观(即架构,损失函数等)。 有没有办法获取这些信息? 最佳答案 仔细阅读文档后,我可以说该功能尚不存在。我什至
本文实例讲述了PHP实现二叉树深度优先遍历(前序、中序、后序)和广度优先遍历(层次)。分享给大家供大家参考,具体如下: 前言: 深度优先遍历:对每一个可能的分支路径深入到不能再深入为止,而且每个
我是一名优秀的程序员,十分优秀!