首页 > 解决方案 > 在 C++ 中构造一个“is_template_instantiable”类型特征

问题描述

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

例如:

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

第一个断言会失败,因为std::optional只需要一个模板参数。第二个断言没有失败,std::vector可以只用一个模板参数实例化,因为它的第二个模板参数有一个默认值。


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

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

因为std::vector可能不会用引用作为其值类型来实例化。


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

标签: c++templatesvariadic-templatesc++17typetraits

解决方案


我假设第一个要求可以通过基于检测习语的方法来实现:

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>);

例子

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


推荐阅读