- iOS/Objective-C 元类和类别
- objective-c - -1001 错误,当 NSURLSession 通过 httpproxy 和/etc/hosts
- java - 使用网络类获取 url 地址
- ios - 推送通知中不播放声音
请考虑以下代码:
struct A
{
virtual ~A() {}
virtual int go() = 0;
};
struct B : public A { int go() { return 1; } };
struct C : public B { int go() { return 2; } };
int main()
{
B b;
B &b_ref = b;
return b_ref.go();
}
在 GCC 4.4.1 下(使用 -O2
),调用 B::go()
得到内联(即,没有虚拟分派(dispatch)发生)。这意味着编译器承认 a_ref
确实指向一个 B
类型变量。 B
引用可用于指向 C
,但编译器足够聪明,可以预见情况并非如此,因此它完全优化了函数调用,内联函数。
太棒了!这是一个令人难以置信的优化。
但是,那么,为什么 GCC 在以下情况下不做同样的事情呢?
struct A
{
virtual ~A() {}
virtual int go() = 0;
};
struct B : public A { int go() { return 1; } };
struct C : public B { int go() { return 2; } };
int main()
{
B b;
A &b_ref = b;
return b_ref.go(); // B::go() is not inlined here, and a virtual dispatch is issued
}
有什么想法吗?其他编译器呢?这种优化常见吗? (我对这种编译器洞察力很陌生,所以我很好奇)
如果第二种情况可行,我可以创建一些非常棒的模板,例如:
template <typename T>
class static_ptr_container
{
public:
typedef T st_ptr_value_type;
operator T *() { return &value; }
operator const T *() const { return &value; }
T *operator ->() { return &value; }
const T *operator ->() const { return &value; }
T *get() { return &value; }
const T *get() const { return &value; }
private:
T value;
};
template <typename T>
class static_ptr
{
public:
typedef static_ptr_container<T> container_type;
typedef T st_ptr_value_type;
static_ptr() : container(NULL) {}
static_ptr(container_type *c) : container(c) {}
inline operator st_ptr_value_type *() { return container->get(); }
inline st_ptr_value_type *operator ->() { return container->get(); }
private:
container_type *container;
};
template <typename T>
class static_ptr<static_ptr_container<T>>
{
public:
typedef static_ptr_container<T> container_type;
typedef typename container_type::st_ptr_value_type st_ptr_value_type;
static_ptr() : container(NULL) {}
static_ptr(container_type *c) : container(c) {}
inline operator st_ptr_value_type *() { return container->get(); }
inline st_ptr_value_type *operator ->() { return container->get(); }
private:
container_type *container;
};
template <typename T>
class static_ptr<const T>
{
public:
typedef const static_ptr_container<T> container_type;
typedef const T st_ptr_value_type;
static_ptr() : container(NULL) {}
static_ptr(container_type *c) : container(c) {}
inline operator st_ptr_value_type *() { return container->get(); }
inline st_ptr_value_type *operator ->() { return container->get(); }
private:
container_type *container;
};
template <typename T>
class static_ptr<const static_ptr_container<T>>
{
public:
typedef const static_ptr_container<T> container_type;
typedef typename container_type::st_ptr_value_type st_ptr_value_type;
static_ptr() : container(NULL) {}
static_ptr(container_type *c) : container(c) {}
inline operator st_ptr_value_type *() { return container->get(); }
inline st_ptr_value_type *operator ->() { return container->get(); }
private:
container_type *container;
};
在许多情况下,这些模板可用于避免虚拟分派(dispatch):
// without static_ptr<>
void func(B &ref);
int main()
{
B b;
func(b); // since func() can't be inlined, there is no telling I'm not
// gonna pass it a reference to a derivation of `B`
return 0;
}
// with static_ptr<>
void func(static_ptr<B> ref);
int main()
{
static_ptr_container<B> b;
func(b); // here, func() could inline operator->() from static_ptr<> and
// static_ptr_container<> and be dead-sure it's dealing with an object
// `B`; in cases func() is really *only* meant for `B`, static_ptr<>
// serves both as a compile-time restriction for that type (great!)
// AND as a big runtime optimization if func() uses `B`'s
// virtual methods a lot -- and even gets to explore inlining
// when possible
return 0;
}
实现它是否可行? (并且不要继续说这是一个微优化,因为它很可能是一个巨大的优化..)
-- 编辑
我刚刚注意到 static_ptr<>
的问题与我暴露的问题无关。指针类型被保留,但它仍然没有内联。我想 GCC 只是没有深入到发现 static_ptr_container<>::value 既不是引用也不是指针的程度。对于那个很抱歉。但问题仍然没有答案。
-- 编辑
我已经制定了一个版本 static_ptr<>
这确实有效。我也稍微更改了名称:
template <typename T>
struct static_type_container
{
// uncomment this constructor if you can't use C++0x
template <typename ... CtorArgs>
static_type_container(CtorArgs ... args)
: value(std::forward<CtorArgs>(args)...) {}
T value; // yes, it's that stupid.
};
struct A
{
virtual ~A() {}
virtual int go() = 0;
};
struct B : public A { int go() { return 1; } };
inline int func(static_type_container<Derived> *ptr)
{
return ptr->value.go(); // B::go() gets inlined here, since
// static_type_container<Derived>::value
// is known to be always of type Derived
}
int main()
{
static_type_container<Derived> d;
return func(&d); // func() also gets inlined, resulting in main()
// that simply returns 1, as if it was a constant
}
唯一的缺点是用户必须访问 ptr->value
得到实际的对象。重载operator ->()
在海湾合作委员会中不起作用。任何返回对实际对象的引用的方法(如果它是内联的)都会破坏优化。真可惜..
最佳答案
这不是一个明确的答案,但我想我还是可以发布它,因为它可能对某些人有用。
评论者Julio Guerra指出了一个名为静态 C++ 面向对象编程 (SCOOP) 的 C++ 习语(他们在论文中称其为“范式”,但我认为这有点过分)。我将发布此消息以提高 SCOOP 的知名度。
SCOOP 的发明是为了让 C++ 程序员能够在 C++ 中很好地协同工作,从而充分利用 OOP 和 GP 世界。它主要针对科学编程,因为它可以带来性能提升,并且可以用于提高代码表达能力。
SCOOP 使 C++ 泛型类型似乎模拟了传统面向对象编程的所有方面 — 静态地。这意味着模板方法具有一些特性,例如,能够正确重载和(显然)发出比通常由您的临时模板函数引起的错误消息更正确的错误消息。
它也可以用来做一些有趣的技巧,比如条件继承。
我试图用 static_ptr<>
完成什么恰恰是一种静态的面向对象。 SCOOP 将其提升到一个全新的水平。
对于那些感兴趣的人,我发现有两篇论文讨论了这个问题:A Static C++ Object-Oriented Programming (SCOOP) Paradigm Mixing Benefits of Traditional OOP and Generic Programming和 Semantics-Driven Genericity: A Sequel to the Static C++ Object-Oriented Programming Paradigm (SCOOP 2) .
不过,这个习语并非没有缺点:它是那些不常见的事情之一,应该是你最后的选择,因为人们很可能很难弄清楚你做了什么,等等。你的代码也会变得更加冗长和您可能会发现自己无法做您认为可能的事情。
不过,我确信它在某些情况下仍然有用,更不用说真正的乐趣了。
快乐的模板破解。
关于c++ - 本地实现的接口(interface)引用,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/4372569/
这个问题在这里已经有了答案: 关闭 10 年前。 Possible Duplicate: template pass by value or const reference or…? 以下对于将函数
我用相同的参数列表重载了一个运算符两次。但返回类型不同: T& operator()(par_list){blablabla} const T& operator()(par_list){bla
假设我有实现接口(interface) I 的 Activity A。我的 ViewModel 类 (VM) 持有对实现接口(interface) I 的对象的引用: class A extends
PHP 如何解释 &$this ?为什么允许? 我遇到了以下问题,这看起来像是 PHP 7.1 和 7.2 中的错误。它与 &$this 引用和跨命名空间调用以及 call_user_func_arr
谁能解释一下下面“&”的作用: class TEST { } $abc =& new TEST(); 我知道这是引用。但是有人可以说明我为什么以及什么时候需要这样的东西吗?或者给我指向一个对此有很好解
引用变量是一个别名,也就是说,它是某个已存在变量的另一个名字。一旦把引用初始化为某个变量,就可以使用该引用名称或变量名称来指向变量。 C++ 引用 vs 指针 引用很容易与指针混淆,它们之间有三
目录 引言 背景 结论 引言 我选择写C++中的引用是因为我感觉大多数人误解了引用。而我之所以有这个感受是因为我主持过很多C++的面试,并且我很少
Perl 中的引用是指一个标量类型可以指向变量、数组、哈希表(也叫关联数组)甚至函数,可以应用在程序的任何地方 创建引用 定义变量的时候,在变量名前面加个 \,就得到了这个变量的一个引用 $sc
我编写了一个将从主脚本加载的 Perl 模块。该模块使用在主脚本中定义的子程序(我不是维护者)。 对于主脚本中的一个子例程,需要扩展,但我不想修补主脚本。相反,我想覆盖我的模块中的函数并保存对原始子例
我花了几个小时试图掌握 F# Quotations,但我遇到了一些障碍。我的要求是从可区分的联合类型中取出简单的函数(只是整数、+、-、/、*)并生成一个表达式树,最终将用于生成 C 代码。我知道使用
很多时候,问题(尤其是那些标记为 regex 的问题)询问验证密码的方法。似乎用户通常会寻求密码验证方法,包括确保密码包含特定字符、匹配特定模式和/或遵守最少字符数。这篇文章旨在帮助用户找到合适的密码
我想通过 MIN 函数内的地址(例如,C800)引用包含文本的最后一个单元格。你能帮忙吗? Sub Set_Formula() ' ----------------------------- Dim
使用常规的 for 循环,我可以做类似的事情: for (let i = 0; i < objects.length; i++) { delete objects[i]; } 常规的 for-
在 Cucumber 中,您定义了定义 BDD 语法的步骤;例如,您的测试可能有: When I navigate to step 3 然后你可以定义一个步骤: When /^I navigate t
这是什么UnaryExpression的目的,以及应该怎样使用? 最佳答案 它需要一个 Expression对象并用另一个 Expression 包裹它.例如,如果您有一个用于 lambda 的表达式
给出以下内容 $("#identifier div:first, #idetifier2").fadeOut(300,function() { // I need to reference jus
我不知道我要找的东西的正确术语,但我要找的是一个完整的引用,可以放在双引号之间的语句,比如 *, node()、@* 以及所有列出的 here加上任何其他存在的。 我链接到的答案提供了一些细节,但还
This question's answers are a community effort。编辑现有答案以改善此职位。它当前不接受新的答案或互动。 这是什么? 这是常见问答的集合。这也是一个社区Wi
Closed. This question does not meet Stack Overflow guidelines。它当前不接受答案。 想改善这个问题吗?更新问题,以便将其作为on-topic
考虑下一个代码: fn get_ref(slice: &'a Vec, f: fn(&'a Vec) -> R) -> R where R: 'a, { f(slice) } fn m
我是一名优秀的程序员,十分优秀!