返回C ++ 11 unique_ptrs父类的函数指针

时间:2013-03-17 00:19:05

标签: c++ c++11 function-pointers unique-ptr

我正在尝试为返回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>')

我很乐意被告知更好的方式来实现我的目标。 : - )

2 个答案:

答案 0 :(得分:2)

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

为了实现这一目标,BarFoo的子类型这一事实必须暗示unique_ptr<struct Bar>将是unique_ptr<struct Foo>的子类型。

有些语言有这个属性,但是C ++没有这个属性,因此很难让模板和继承很好地协同工作。在Java中你会写这个:

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

其中UniquePtr<? extends Foo> f声明一个在其类型参数中具有协变性的变量。

我猜你必须找到一种以某种方式解决这个问题的设计。 This post似乎包含了类似的问题,可能会提出一些建议。

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

答案 1 :(得分:1)

这是我用来解决我的特定问题的修改设计。我使用新的C ++ 11模板using声明来标记将返回的特定类型。当我调用该函数时,我利用unique_ptr的能力进行上传而没有任何问题。

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;
}