如何仅从类类型推导类构造函数的参数类型

时间:2019-08-11 13:57:42

标签: c++ templates

在模板元编程中,有一个窍门:

template <typename T>
struct my_struct {};

template <typename... T1, typename... Ts>
struct my_struct <std::tuple<T1, Ts...>>
{
    // Tuple is "unpacked"
    // I can freely work on 'T1' & 'Ts' types (through recursion) in this scope.
    using type = T1;
};

我希望成员函数(尤其是构造函数)存在类似的技巧:

template <typename T>
struct my_struct {};

// specialisation for case when type 'T' has 'T(U1, Us...)' ctor.
template <typename T, typename U1, typename... Us>
struct my_struct <
    decltype(T::T(
        std::declval<U1>(), 
        std::declval<Us>()...
    ))
>
{
    using type = U1;
};

不幸的是,这会导致错误:

  

模板参数“ U1”和参数包“ Us”未在类模板“ my_struct”的模板参数列表中使用或无法推导出来

有没有办法获取T的ctor参数的类型?


我需要上面的内容,因为我有一个函数func<T>(),对于类型T具有T(std::initializer_list</* ??? */>)构造函数的情况,必须对其进行“专门化”(/“重载”)。

template<typename T>
struct get_init_list_type_from_T_ctor 
{
    // magic happens here
};

template<typename T>
using has_init_list_ctor = std::enable_if_t<
    std::is_constructible_v<
        T,
        std::initializer_list<
            typename get_init_list_type_from_T_ctor<T>::type
        >
    >
>;

// version for T with initialization list ctor
template<
    typename T,
    typename = std::enable_if_t<
        std::is_detected_v<has_init_list_ctor, T>
    >
>
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>
    >
>
void func() {
    //... 
}

1 个答案:

答案 0 :(得分:0)

不可能在C ++中强制执行特定的构造函数签名。

但是,如果初始化列表的类型是固定的,您仍然可以通过使用必需的参数调用构造函数来利用SFINAE:

template <typename T, typename U>
struct has_init_list_ctor
    : std::is_constructible<T, std::initializer_list<U>>
{
};

template <typename T, typename U>
inline constexpr bool has_init_list_ctor_v = has_init_list_ctor<T, U>::value;

如果您不知道初始化列表的类型,则此方法将无效。我们必须等待Reflection TS。如果真是这样,我想不出这怎么可能有用。