C++:如何从 make_shared 部分推导模板参数
C++: How to partially deduce template arguments from make_shared
为了规避 ,我将要从中推导出 class 模板参数 (Internal
) 的结构嵌入到第二个结构 (Container
).
我想让代码的用户能够创建例如结果类型的共享指针。通过在结构中编写我自己的 create
函数,这工作得很好。
#include <memory>
/// Container that is used in order to partially specify template arguments
template <int A> struct Container {
/// Contained type, of which the template arguments are deduced.
template <int B> struct Internal {
explicit Internal(std::integral_constant<int, B> fu) { (void)fu; }
};
/// Helper function
template <int C>
[[nodiscard]] static auto create(std::integral_constant<int, C> t) noexcept {
return std::make_shared<Container<A>::Internal<C>>(t);
}
};
int main() {
Container<1>::Internal works{std::integral_constant<int, 8>{}};
auto const worksAswell = Container<1>::create(std::integral_constant<int, 8>{});
}
但是当我尝试直接使用 make_shared 时,它失败了。我想让用户使用例如std::make_shared 函数。
int main() {
auto const fails = std::make_shared<Container<1>::Internal>(std::integral_constant<int, 8>{});
}
据我所知,这失败了,因为我不能部分指定模板参数,如果我不想指定所有模板参数,我将无法从 make_shared 函数中推断出它们。
main.cc: In function ‘int main()’:
main.cc:21:74: error: no matching function for call to ‘make_shared<1>(std::integral_constant<int, 8>)’
21 | auto const fails = std::make_shared<1>(std::integral_constant<int, 8>{});
| ^
In file included from /usr/include/c++/9.2.0/memory:81,
from /home/juli/main9.cc:1:
/usr/include/c++/9.2.0/bits/shared_ptr.h:714:5: note: candidate: ‘template<class _Tp, class ... _Args> std::shared_ptr<_Tp> std::make_shared(_Args&& ...)’
714 | make_shared(_Args&&... __args)
| ^~~~~~~~~~~
/usr/include/c++/9.2.0/bits/shared_ptr.h:714:5: note: template argument deduction/substitution failed:
是否可以启用像 std::make_shared
这样的生成器函数来部分推导出这样的模板参数?完整代码可以在here.
找到
如果您创建自己的接受模板模板参数的 make_shared
,我们可以使用 decltype
推断结果类型并将其传递给 std::make_shared
。
#include <memory>
#include <type_traits>
/// Container that is used in order to partially specify template arguments
template <int A> struct Container {
/// Contained type, of which the template arguments are deduced.
template <int B> struct Internal {
explicit Internal(std::integral_constant<int, B> fu) { (void)fu; }
};
};
template <template <int> typename partial, typename... Args>
auto make_shared(Args&&... args) {
using target_type = std::remove_pointer_t<decltype(new partial{std::declval<Args>()...})>;
return std::make_shared<target_type>(std::forward<Args>(args)...);
}
using std::make_shared;
int main() {
auto const fails = make_shared<Container<1>::Internal>(std::integral_constant<int, 8>{});
static_assert(std::is_same_v<const std::shared_ptr<Container<1>::Internal<8>>, decltype(fails)>);
}
这里唯一的问题是我们的 make_shared
需要知道预期目标的模板签名。
积极的一面是,我们可以为不同的模板签名添加多个重载,并且我们可以使用一个参数包。
为了规避 Internal
) 的结构嵌入到第二个结构 (Container
).
我想让代码的用户能够创建例如结果类型的共享指针。通过在结构中编写我自己的 create
函数,这工作得很好。
#include <memory>
/// Container that is used in order to partially specify template arguments
template <int A> struct Container {
/// Contained type, of which the template arguments are deduced.
template <int B> struct Internal {
explicit Internal(std::integral_constant<int, B> fu) { (void)fu; }
};
/// Helper function
template <int C>
[[nodiscard]] static auto create(std::integral_constant<int, C> t) noexcept {
return std::make_shared<Container<A>::Internal<C>>(t);
}
};
int main() {
Container<1>::Internal works{std::integral_constant<int, 8>{}};
auto const worksAswell = Container<1>::create(std::integral_constant<int, 8>{});
}
但是当我尝试直接使用 make_shared 时,它失败了。我想让用户使用例如std::make_shared 函数。
int main() {
auto const fails = std::make_shared<Container<1>::Internal>(std::integral_constant<int, 8>{});
}
据我所知,这失败了,因为我不能部分指定模板参数,如果我不想指定所有模板参数,我将无法从 make_shared 函数中推断出它们。
main.cc: In function ‘int main()’:
main.cc:21:74: error: no matching function for call to ‘make_shared<1>(std::integral_constant<int, 8>)’
21 | auto const fails = std::make_shared<1>(std::integral_constant<int, 8>{});
| ^
In file included from /usr/include/c++/9.2.0/memory:81,
from /home/juli/main9.cc:1:
/usr/include/c++/9.2.0/bits/shared_ptr.h:714:5: note: candidate: ‘template<class _Tp, class ... _Args> std::shared_ptr<_Tp> std::make_shared(_Args&& ...)’
714 | make_shared(_Args&&... __args)
| ^~~~~~~~~~~
/usr/include/c++/9.2.0/bits/shared_ptr.h:714:5: note: template argument deduction/substitution failed:
是否可以启用像 std::make_shared
这样的生成器函数来部分推导出这样的模板参数?完整代码可以在here.
如果您创建自己的接受模板模板参数的 make_shared
,我们可以使用 decltype
推断结果类型并将其传递给 std::make_shared
。
#include <memory>
#include <type_traits>
/// Container that is used in order to partially specify template arguments
template <int A> struct Container {
/// Contained type, of which the template arguments are deduced.
template <int B> struct Internal {
explicit Internal(std::integral_constant<int, B> fu) { (void)fu; }
};
};
template <template <int> typename partial, typename... Args>
auto make_shared(Args&&... args) {
using target_type = std::remove_pointer_t<decltype(new partial{std::declval<Args>()...})>;
return std::make_shared<target_type>(std::forward<Args>(args)...);
}
using std::make_shared;
int main() {
auto const fails = make_shared<Container<1>::Internal>(std::integral_constant<int, 8>{});
static_assert(std::is_same_v<const std::shared_ptr<Container<1>::Internal<8>>, decltype(fails)>);
}
这里唯一的问题是我们的 make_shared
需要知道预期目标的模板签名。
积极的一面是,我们可以为不同的模板签名添加多个重载,并且我们可以使用一个参数包。