在 C++ 中构造一个 'is_template_instantiable' 类型特征

Construct an 'is_template_instantiable' type trait in C++

是否可以在 C++ 中构造一个类型特征来检查给定的模板类型是否可以用给定的类型作为模板参数实例化?如果可以,怎么做到的?

例如:

static_assert(is_template_instantiable_v<std::optional, int, int>);
static_assert(is_template_instantiable_v<std::vector, double>);

第一个断言会失败,因为 std::optional expects only a single template parameter. The second assert does not fail, std::vector 可能只用一个模板参数实例化,因为它的第二个模板参数有默认值。


如果上述可行,是否可以在以下情况下让类型特征为假(并且不触发编译错误):

static_assert(is_template_instantiable_v<std::vector, int &>);

因为std::vector可能无法以引用作为其值类型来实例化。


我的猜测是第一个示例可能可以复制,而第二个示例仅使用标准 C++ 代码无法完成。

我假设第一个要求可以通过基于 detection idiom:

的方法实现
namespace detail
{
    template<template<typename...> typename T, typename AlwaysVoid, typename... Ts>
    struct is_template_instantiable :
        std::false_type {};

    template<template<typename...> typename T, typename... Ts>
    struct is_template_instantiable<T, std::void_t<T<Ts...>>, Ts...> :
        std::true_type {};

    template<template<typename...> typename T, typename... Ts>
    inline constexpr auto is_template_instantiable_v =
        is_template_instantiable<T, void, Ts...>::value;
}

然后,用:

template<typename T = void>
struct X{};

它产生:

static_assert(detail::is_template_instantiable_v<X>);
static_assert(detail::is_template_instantiable_v<X, void>);
static_assert(!detail::is_template_instantiable_v<X, void, int>);

EXAMPLE

然而,由于这种类型特征,我无法解决第二个挑战...