Moc*_*han 6 c++ templates pointers
我有一个函数可以创建的基础类型的新对象P。这P是一种可取消引用的类型,如指针或智能指针。
template<typename P>
auto make_new()
Run Code Online (Sandbox Code Playgroud)
例如,对于指针和智能指针,
struct A
{
int a = 3;
};
A* a = make_new<A*>();
std::cout << a->a << std::endl;
delete a;
std::shared_ptr<A> b = make_new<std::shared_ptr<A>>();
std::cout << b->a << std::endl;
Run Code Online (Sandbox Code Playgroud)
现在,对于共享指针,我将实现make_new以下内容,
template<typename P>
auto make_new()
{
using Ptype = typename P::element_type;
return P(new Ptype);
}
Run Code Online (Sandbox Code Playgroud)
这不适用于指针。
现在,既适用于指针又适用于智能指针的东西,
template<typename P>
auto make_new()
{
using Ptype = typename std::remove_reference<decltype(*P())>::type;
return P(new Ptype);
}
Run Code Online (Sandbox Code Playgroud)
但不适用于std::optional。
有没有一种规范的方法来获取可取消引用对象的基础类型?
我知道,*并且->可以重载到任何东西,并且不能保证构造函数可以像上面那样工作,或者说有意义。
只是想知道是否有一种方法,而不仅仅是找到它,或者只是做一些愚蠢的事情。
目标。我们的目标是编写一个using模板,该模板采用可解除引用的类型作为输入,并返回元素类型。
template<class T>
using element_type_t = /* stuff */;
Run Code Online (Sandbox Code Playgroud)
方法。我们可以使用SFINAE来检查是否有一个element_type属性,如果没有,则退回到使用std::remove_reference<decltype(*P())>()。
// This is fine to use in an unevaluated context
template<class T>
T& reference_to();
// This one is the preferred one
template<class Container>
auto element_type(int)
-> typename Container::element_type;
// This one is the fallback if the preferred one doesn't work
template<class Container>
auto element_type(short)
-> typename std::remove_reference<decltype(*reference_to<Container>())>::type;
Run Code Online (Sandbox Code Playgroud)
一旦有了此功能,我们就可以element_type_t通过获取的返回类型来进行编写element_type。
// We alias the return type
template<class T>
using element_type_t = decltype(element_type<T>(0));
Run Code Online (Sandbox Code Playgroud)
为什么我们不能总是通过取消引用来获取element_type?如果尝试始终使用*运算符获取值类型,则可能会导致诸如for的迭代器之类的问题,该迭代器std::vector<bool>返回的行为类似于bool,但封装了位操作。在这些情况下,元素类型与通过取消引用返回的类型不同。
您的代码失败的原因std::optional是因为std::optional的构造函数本身是值,而不是指向值的指针。为了确定我们需要哪个构造函数,我们再次使用SFINAE进行确定。
// Base case - use new operator
template<class Container>
auto make_new_impl(int)
-> decltype(Container{new element_type_t<Container>})
{
return Container{new element_type_t<Container>};
}
// Fallback case, where Container takes a value
template<class Container>
auto make_new_impl(long)
-> decltype(Container{element_type_t<Container>()})
{
return Container{element_type_t<Container>()};
}
Run Code Online (Sandbox Code Playgroud)
现在,我们可以编写make_new它调用make_new_impl:
template<class Container>
auto make_new() {
return make_new_impl<Container>(0);
}
Run Code Online (Sandbox Code Playgroud)
例。我们现在可以使用make_new,使两种std::optional,std::shared_ptr或者甚至一个普通的指针。
#include <optional>
#include <memory>
int main() {
// This works
int* ptr = make_new<int*>();
// This works too
std::shared_ptr<int> s = make_new<std::shared_ptr<int>>();
// This also works
std::optional<int> o = make_new<std::optional<int>>();
}
Run Code Online (Sandbox Code Playgroud)