初始化和分配值,从引用传递

时间:2009-09-10 15:13:42

标签: c++

好的,这只是一个小小的警告。我目前正在与ESRI的可爱ArcSDK合作。现在要从他们的任何函数中获取值,你基本上必须传递变量,你想要赋值给。

E.g:

long output_width;
IRasterProps->get_Width(&output_width);

这是一件小事,但是当你必须从他们的各种功能中挑出大约30个不同的数据时,它真的开始变得烦人。

所以我想知道是否有可能通过STL或C ++的魔力以某种方式将其改为:

long output_width = IRasterProps->get_Width(<something magical>);

所有函数都返回void,否则它们中的一些可能会返回一个HRESULT,我可以放心地忽略它。有什么想法吗?

*** **** EDIT

继承了我得到的最终结果:)!!!!!

A magic(P p, R (__stdcall T::*f)(A *)) {
    A a;
    ((*p).*f)(&a);
    return a;
}

7 个答案:

答案 0 :(得分:7)

我知道我已经回答了,但这是另一种方式。它更好,因为它更快(没有boost ::函数开销)并且避免了绑定器(因为人们似乎厌恶它们),但更糟糕的是它不那么通用(因为它只适用于单参数成员函数) )。

template <typename P, typename T, typename A>
A magic(P p, void (T::*f)(A &)) {
    A a;
    ((*p).*f)(a);
    return a;
}

您可以这样称呼:

long output_width = magic(raster_props_object, &IRasterProps::get_Width);

或者,如果你碰巧使用GCC,我们可以使用更多技巧:

#define MORE_MAGIC(p,f) ({ \
    typedef __typeof(*(p)) big_ugly_identifier; \
    magic((p),(&big_ugly_identifier::f)); \
})

让我们这样做:

long output_width = MORE_MAGIC(raster_props_object, get_Width);

(如果命名惯例让您想到PDP-10,则可获得奖励。)

编辑:更新为采用任何类似指针的类型,因此它现在可以使用shared_ptr,迭代器,并希望_com_ptr。

编辑:糟糕,它们是指针,而不是引用。这是一个处理它的版本(或重载),并允许 - 通过忽略 - 任意类型的返回值。

template <typename P, typename T, typename A, typename R>
A magic(P p, R (T::*f)(A *)) {
    A a;
    ((*p).*f)(&a);
    return a;
}

答案 1 :(得分:2)

这不是你指定的,因为你需要在方法周围包装get(),但它可以工作:

template<class T, class S>
T get(S fun(T&)) {
  T result;
  fun(result);
  return result;
}

void foo(int& x) {
  x = 5;
}

bool bar(char& x) {
  x = 'c';
  return false;
}

int main() {
  int x = get(foo);
  char y = get(bar);

  return 0;
}

答案 2 :(得分:1)

编辑:回想起来,我不确定这个实际上是否有效,因为我认为模板参数不会推断出来。买家当心。

当然!你需要的是你可以传递一个函数来调用它并返回输出值。

这是一种简单易用的方式:

template <typename T>
T magic(boost::function<void(T&)> f) {
    T x;
    f(x);
    return x;
}

然后使用boost :: lambda:

进行调用
long output_width = magic(raster_props_object->*&IRasterProps::get_Width);

或者像这样,使用boost :: bind:

long output_width = magic(bind(&IRasterProps::get_Width, raster_props_object, _1));

你可以摆脱boost :: function,但那更加丑陋。不过可能值得。

答案 3 :(得分:1)

你能从IRasterProps派生出来吗?因此,您可以构建自己的接口。

编辑:根据这个概念,您可以应用适配器设计模式(如果您希望将一个通用接口应用于几个相似的SDK类),甚至可以应用Facade。

答案 4 :(得分:1)

看起来像我的COM对象。 Visual C ++支持#import指令来导入类型库,并创建高级别的包装器。所以你最终得到了

width = ptr->GetWidth();

或 - 甚至更好 -

width = ptr->Width;

如果函数失败,返回的HRESULT将转换为_com_error异常。

我在许多操作系统和第三方COM对象上成功使用它,使它们更容易使用。

请注意,您通过选项控制包装器生成,我做的第一件事通常是添加rename_namespaceno_namespace,因为否则symbold最终会在名称空间中根据类型库名称进行操作,通常是丑陋的。

另外,除非您使用named_guids选项,否则可能需要将CLSID_xxxIID_xxx常量更改为__uuidof(xxx)

答案 5 :(得分:0)

不要认为这是可能的。在任何情况下,将void分配给long应该是一个错误。

请记住,传递引用可能比返回大对象更高效。 (虽然不会对长期有所影响)

编译:

void foo(long &a) {
}

    int main(void) {

    long a=0;
    a = foo(a);
    return 0;
}

给出了这个错误:

g++ x.cc 
x.cc: In function ‘int main()’:
x.cc:9: error: void value not ignored as it ought to be

答案 6 :(得分:0)

我不知道你能做些什么疯狂,就像你问的那样,如果有一些疯狂的hackery在一些特殊的平台上工作,我很确定在代码审查中我讨厌它

可能更有意义......

  • 围绕您关心的API定义一些简单的内联函数包装

  • 从IRasterProps(或其他)提供一个专门的类,它提供适当的访问器方法。

其中任何一个都会影响代码的维护时间,但会安全,干净地为您提供您正在寻找的调用语法。