2

我正在尝试为返回unique_ptr实例的函数创建函数指针。每个函数都应该返回一个尽可能具体类型的值,以便对许多调用者普遍有用(在我的真实代码中,函数被命名为构造函数,并且在每个对象的公共标头中)。然而,在这个特定的用途中,我只关心每个类实现的通用接口。

我遇到了一个问题,我无法将返回的函数分配给返回unique_ptr<Subclass>的函数指针unique_ptr<Superclass>

我把我的例子归结为这个片段:

#include <iostream>
#include <memory>

struct Foo {
  virtual void foo() = 0;
};

struct Bar : public Foo {
  void foo() {};
};

std::unique_ptr<Foo>
foo_creator()
{
  return nullptr;
}

std::unique_ptr<Bar>
bar_creator()
{
  return nullptr;
}

typedef std::unique_ptr<Foo>(*creator_fn)();

int
main(int argc, char *argv[])
{
  std::unique_ptr<Foo> f;

  f = foo_creator();
  f = bar_creator();

  creator_fn foo_fn = foo_creator;
  creator_fn bar_fn = bar_creator; // Fails

  return 0;
}

我从 clang ( Apple LLVM version 4.2 (clang-425.0.24) (based on LLVM 3.2svn)) 得到的编译错误是:

cannot initialize a variable of type 'creator_fn'
(aka 'std::unique_ptr<Foo> (*)()') with an lvalue
of type 'std::unique_ptr<Bar> ()':

different return type
('unique_ptr<struct Foo>' vs 'unique_ptr<struct Bar>')

我也愿意被告知实现目标的更好方法。:-)

4

2 回答 2

2

编译此代码所需的功能称为类型参数的协方差。查看有关该主题的Wikipedia 文章

为此,作为 to 的子类型的事实Bar必须Foo暗示这unique_ptr<struct Bar>将是 to 的子类型unique_ptr<struct Foo>

一些语言有这个属性,但 C++ 没有,这使得模板和继承很难很好地结合在一起。在 Java 中,你会这样写:

UniquePtr<? extends Foo> f;
f = fooCreator();
f = barCreator();

WhereUniquePtr<? extends Foo> f声明了一个在其类型参数中协变的变量。

我想你必须找到一个以某种方式解决这个问题的设计。这篇文章似乎包含一个类似的问题,可能会给出一些建议。

编辑:我误读了这个问题,并认为编译错误在错误的行上,所以上面的答案有点误导。我仍然认为缺乏差异是问题所在,但这一行出现了错误:bar_fn = bar_creator; // Fails

于 2013-03-17T00:52:23.960 回答
1

这是我用来解决我的特定问题的修改设计。我使用新的 C++11 模板using声明来标记将返回的特定类型。当我调用该函数时,我unique_ptr可以毫无问题地利用 s 向上转换的能力。

template <class T>
using creator_fn = std::unique_ptr<T>(*)();

int
main(int argc, char *argv[])
{
  std::unique_ptr<Foo> f;

  f = foo_creator();
  f = bar_creator();

  creator_fn<Foo> foo_fn = foo_creator;
  creator_fn<Bar> bar_fn = bar_creator;

  f = foo_fn();
  f = bar_fn();

  return 0;
}
于 2013-03-17T13:40:57.110 回答