【发布时间】:2019-08-11 21:00:21
【问题描述】:
我有一个函数func <T> (...),它必须分成两个分支;
第一个分支:
T类型具有T(std::initializer_list<U>)构造函数的情况。第二个分支:
T类型没有T(std::initializer_list<U>)构造函数的情况。
我目前的实现如下:
template<typename T, typename U>
using has_init_list_ctor = std::enable_if_t<std::is_constructible_v<
T,
std::initializer_list<U>
>>;
// version for T with initialization list ctor
template<
typename T,
typename = std::enable_if_t<
std::is_detected_v<has_init_list_ctor, T, /* idk how to auto-deduce type U */>
>
>
void func() {
//...
}
// version for T without initialization list ctor
template<
typename T,
typename = std::enable_if_t<
!std::is_detected_v<has_init_list_ctor, T, /* idk how to auto-deduce type U */>
>
>
void func() {
//...
}
但它有一个缺陷。我不知道如何从T 自动推断类型U。
理想的解决方案是:
template<typename T>
struct deduce_U_from_T
{
// implementation.
usign type = /* ??? */;
};
template<typename T>
using has_init_list_ctor = std::enable_if_t<std::is_constructible_v<
T,
std::initializer_list<
typename deduce_U_from_T<T>::type
>
>>;
但我不知道如何实现deduce_U_from_T。
有什么办法可以解决这个问题吗? 或者有什么解决方法吗?
更新:
函数func <T> (...) 是对std::alocator_traits::construct() 的模仿。
我正在尝试实现我自己的“分配器”以使用std::vector 和智能指针。一般情况下,我会使用默认的std::alocator_traits,但是这一次,我需要从“特殊”池中请求内存(这是我自己实现的,可以称为“虚拟堆”,通过方法访问)像T * get_memory <T> (...),池在内存分配期间执行额外的操作,并提供不同的分配“模式” - 很抱歉非常通用,但目前它是 WIP,它会不断变化)
func <T> (...) (allocator_traits::construct()) 的简单实现
template<typename T>
class allocator_traits
{
//...
public:
template<typename... Args>
static
std::enable_if_t<
std::is_detected_v<has_init_list_ctor, T>,
void
> construct(T * ptr, Args && ... args)
{
new(ptr) T(std::forward<Args>(args)...); // normal brackets // construct with placment-new
}
template<typename... Args>
static
std::enable_if_t<
!std::is_detected_v<has_init_list_ctor, T>,
void
> construct(T * ptr, Args && ... args)
{
new(ptr) T{ std::forward<Args>(args)... }; // curly brackets // construct with placment-new
}
//...
};
不同之处在于可以使用大括号构造类型 T(当类型 T 没有 T(std::initializer_list<U>) 构造函数时。
【问题讨论】:
-
XY 问题?
func()究竟要做什么,你为什么关心T是否有一个initializer_list<U>构造函数用于一些任意的U(而不是一些特定的U)? -
这只有在
U是离散类型时才有可能。如果是必须推导的模板类型,恐怕是不可能的。 C++ 不能以这种方式工作。 -
如果不出意外,
T可能有多个构造函数将std::initializer_list<U>用于不同的U。仅出于这个原因,“从T自动推断类型U”的目标可能是没有希望的。为什么你觉得你需要这个?听起来像XY problem -
U不是std::common_type_t<Args...>吗? -
@Jarod42 No.
U甚至可能与Args...没有任何关系。考虑vector<char>{1, 2, 3}或vector<string>{"a", "bc", "def"}
标签: c++ templates constructor c++17 sfinae