std::map 可以包含对构造函数的引用吗?
Can a std::map contain a reference to a constructor?
有没有办法从 std::map 指向构造函数?我想使用我希望在 #if 0
中使用的代码执行以下操作,但我似乎无法让它工作:
#include <map>
#include <functional>
using namespace std;
class Base { };
class A : public Base { };
class B : public Base { };
enum class Type { A, B, };
#if 0
using type_map_t = std::map<Type, std::function<Base*()>>;
type_map_t type_map = {
{Type::A, &A::A},
{Type::B, &B::B},
};
#endif
Base*
getBase(Type t)
{
#if 0
auto constructor = type_map[t];
return constructor();
#else
switch(t)
{
case Type::A:
return new A();
case Type::B:
return new B();
}
#endif
}
int
main(int argc, char *argv[])
{
Base *base = getBase(Type::A);
return 0;
}
与其在 getBase 中使用 switch 语句,不如让映射指示为每种类型调用的构造函数。
std::function 想到如何执行此操作,但似乎无法在 C++ 中获取构造函数的地址。有没有一种优雅的方式来完成我想在这里做的事情?
根据 C++ 标准,您不能获取构造函数的地址
(C++98/03 的第 12.1.12 节和 C++11 的第 12.1.10 节):
Constructors - The address of a constructor shall not be taken.
对于这个问题,典型的解决方案是创建特定的 factories/methods 来创建对象。
虽然无法直接获取指向构造函数的指针,但您可以创建自己的构造函数对象:
template<class Sig>
struct ctor_t;
template<class T, class...Args>
struct ctor_t<T(Args...)> {
T* operator()(Args...args)const {
return new T(std::forward<Args>(args)...);
}
T* operator()(void*p, Args...args)const {
return new(p) T(std::forward<Args>(args)...);
}
using simple = T*(*)(Args...args);
using placement = T*(*)(void*, Args...args);
operator simple()const {
return [](Args...args)->T* {
return ctor_t{}(std::forward<Args>(args)...);
};
}
operator placement()const {
return [](void*p, Args...args)->T* {
return ctor_t{}(p, std::forward<Args>(args)...);
};
}
};
template<class Sig>
static const ctor_t<Sig> ctor = {};
它可以让你创建一个像构造函数一样的对象,也可以变成一个函数指针。
上面使用了一些C++14。将 ctor
替换为:
template<class Sig>
constexpr ctor_t<Sig> ctor() { return {}; }
及其对 C++11(无变量模板)从 ctor<A()>
到 ctor<A()>()
的使用。
几点:
构造函数是一段获取原始内存并将其转换为对象的代码。这意味着您必须拥有恰到好处的可用内存量。
没有像普通函数那样访问构造函数的机制,因为:构造函数的 this
指针在构造开始时就已经知道了,没有办法传递一个在。
解决这些限制的方法是使用 operator new
。通常的 operator new
将分配对象所需的内存,如果分配成功则应用构造函数代码。 (或者,有一个 "placement new
" 允许程序员为对象提供指向 "enough memory" 的指针。它用于 "emplaced" 构造,您已经预先在其中分配了合适的缓冲区。通常这些东西只存在于容器库中。)
因此,您在地图中放置的内容将不得不在函数中使用 new
。通常的 new
就可以了,因为您没有任何传递原始内存的机制。
使用 lambda,您的地图可能如下所示:
type_map_t type_map = {
{Type::A, []() -> Base* { return new A; } },
{Type::B, []() -> Base* { return new B; } },
};
构造 []() -> Base*
表示以下代码块被视为不带参数的函数体(()
-列表中没有任何内容),并且周围范围没有任何内容([]
-列表),并返回一个 Base*
。它可用作 std::function<Base*()>
holder 对象的初始化值。
你也可以直接调用你的地图条目:
Base* base = type_map[Type::A]();
有没有办法从 std::map 指向构造函数?我想使用我希望在 #if 0
中使用的代码执行以下操作,但我似乎无法让它工作:
#include <map>
#include <functional>
using namespace std;
class Base { };
class A : public Base { };
class B : public Base { };
enum class Type { A, B, };
#if 0
using type_map_t = std::map<Type, std::function<Base*()>>;
type_map_t type_map = {
{Type::A, &A::A},
{Type::B, &B::B},
};
#endif
Base*
getBase(Type t)
{
#if 0
auto constructor = type_map[t];
return constructor();
#else
switch(t)
{
case Type::A:
return new A();
case Type::B:
return new B();
}
#endif
}
int
main(int argc, char *argv[])
{
Base *base = getBase(Type::A);
return 0;
}
与其在 getBase 中使用 switch 语句,不如让映射指示为每种类型调用的构造函数。
std::function 想到如何执行此操作,但似乎无法在 C++ 中获取构造函数的地址。有没有一种优雅的方式来完成我想在这里做的事情?
根据 C++ 标准,您不能获取构造函数的地址 (C++98/03 的第 12.1.12 节和 C++11 的第 12.1.10 节):
Constructors - The address of a constructor shall not be taken.
对于这个问题,典型的解决方案是创建特定的 factories/methods 来创建对象。
虽然无法直接获取指向构造函数的指针,但您可以创建自己的构造函数对象:
template<class Sig>
struct ctor_t;
template<class T, class...Args>
struct ctor_t<T(Args...)> {
T* operator()(Args...args)const {
return new T(std::forward<Args>(args)...);
}
T* operator()(void*p, Args...args)const {
return new(p) T(std::forward<Args>(args)...);
}
using simple = T*(*)(Args...args);
using placement = T*(*)(void*, Args...args);
operator simple()const {
return [](Args...args)->T* {
return ctor_t{}(std::forward<Args>(args)...);
};
}
operator placement()const {
return [](void*p, Args...args)->T* {
return ctor_t{}(p, std::forward<Args>(args)...);
};
}
};
template<class Sig>
static const ctor_t<Sig> ctor = {};
它可以让你创建一个像构造函数一样的对象,也可以变成一个函数指针。
上面使用了一些C++14。将 ctor
替换为:
template<class Sig>
constexpr ctor_t<Sig> ctor() { return {}; }
及其对 C++11(无变量模板)从 ctor<A()>
到 ctor<A()>()
的使用。
几点:
构造函数是一段获取原始内存并将其转换为对象的代码。这意味着您必须拥有恰到好处的可用内存量。
没有像普通函数那样访问构造函数的机制,因为:构造函数的
this
指针在构造开始时就已经知道了,没有办法传递一个在。 解决这些限制的方法是使用operator new
。通常的operator new
将分配对象所需的内存,如果分配成功则应用构造函数代码。 (或者,有一个 "placementnew
" 允许程序员为对象提供指向 "enough memory" 的指针。它用于 "emplaced" 构造,您已经预先在其中分配了合适的缓冲区。通常这些东西只存在于容器库中。)
因此,您在地图中放置的内容将不得不在函数中使用 new
。通常的 new
就可以了,因为您没有任何传递原始内存的机制。
使用 lambda,您的地图可能如下所示:
type_map_t type_map = {
{Type::A, []() -> Base* { return new A; } },
{Type::B, []() -> Base* { return new B; } },
};
构造 []() -> Base*
表示以下代码块被视为不带参数的函数体(()
-列表中没有任何内容),并且周围范围没有任何内容([]
-列表),并返回一个 Base*
。它可用作 std::function<Base*()>
holder 对象的初始化值。
你也可以直接调用你的地图条目:
Base* base = type_map[Type::A]();