gpt4 book ai didi

c++ - 本地实现的接口(interface)引用

转载 作者:塔克拉玛干 更新时间:2023-11-03 02:13:19 24 4
gpt4 key购买 nike

请考虑以下代码:

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 ProgrammingSemantics-Driven Genericity: A Sequel to the Static C++ Object-Oriented Programming Paradigm (SCOOP 2) .

不过,这个习语并非没有缺点:它是那些不常见的事情之一,应该是你最后的选择,因为人们很可能很难弄清楚你做了什么,等等。你的代码也会变得更加冗长和您可能会发现自己无法做您认为可能的事情。

不过,我确信它在某些情况下仍然有用,更不用说真正的乐趣了。

快乐的模板破解。

关于c++ - 本地实现的接口(interface)引用,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/4372569/

24 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com