【问题标题】:Doing a static_assert that a template type is another template做一个静态断言模板类型是另一个模板
【发布时间】:2013-06-27 18:08:13
【问题描述】:

我怎么static_assert 这样的?如果不是 C++ 或 C++11 中的新功能,也许 Boost 支持它?

template<T>
struct foo {};

template<FooType>
struct bar {
  static_assert(FooType is indeed foo<T> for some T,"failure"); //how?
};

【问题讨论】:

  • 相关问题可以找here

标签: c++ templates boost c++11


【解决方案1】:

你可以按照这些思路做一些事情。给定一个可以验证类是否是类模板的实例化的特征:

#include <type_traits>

template<typename T, template<typename> class TT>
struct is_instantiation_of : std::false_type { };

template<typename T, template<typename> class TT>
struct is_instantiation_of<TT<T>, TT> : std::true_type { };

在你的程序中如下使用它:

template<typename T>
struct foo {};

template<typename FooType>
struct bar {
  static_assert(is_instantiation_of<FooType, foo>::value, "failure");
};

int main()
{
    bar<int> b; // ERROR!
    bar<foo<int>> b; // OK!
}

如果您愿意,可以将其概括为检测一个类是否是具有任意数量(类型)参数的模板的实例,如下所示:

#include <type_traits>

template<template<typename...> class TT, typename T>
struct is_instantiation_of : std::false_type { };

template<template<typename...> class TT, typename... Ts>
struct is_instantiation_of<TT, TT<Ts...>> : std::true_type { };

template<typename FooType>
struct bar {
  static_assert(is_instantiation_of<foo, FooType>::value, "failure");
};

然后你会在你的程序中这样使用它:

template<typename FooType>
struct bar {
  static_assert(is_instantiation_of<foo, FooType>::value, "failure");
};

int main()
{
    bar<int> b; // ERROR!
    bar<foo<int>> b; // OK!
}

这是live example

【讨论】:

  • 您(或这里的其他人)是否认为通过阅读 Vandevoorde 和 Josuttis 所著的《C++ 模板:完整指南》一书所获得的知识可以让我自己做到这一点?
  • 嗯,可能不是,因为std::true_type 是 C++11 的一个特性 :( 似乎没有任何新的 C++11 模板书籍。
  • @roger.james:这是一本好书,我还是建议您阅读。但是,正如您所提到的,在这个答案中,我使用了该书中未介绍的 C++11 功能(尤其是可变参数模板)。
  • 是否可以进一步概括它以使类型别名成功?当前失败的示例:gist.github.com/anonymous/d318fcac90651bcffa5e
  • 这里有两种选择: 1) 所有的别名都是等价的。 2) 如果原来使用 foo_alt,则只有 foo_alt(而不是 foo)会在 static_assert 中成功,反之亦然。两个版本都可以实现吗?
【解决方案2】:

对其他答案的一些小改进:

  • 这个名字实际上对参数的顺序有意义
  • 通过 std::decay 正确处理 constvolatile 和引用类型
  • 实现 C++14 风格的 _v constexpr 变量
  • 接受任意数量的类型进行测试(针对 ALL 的测试)

我故意不将 std::decay_t 放在 is_template_for_v 上,因为无论是否使用 _v 后缀调用类型特征,它都应该同样工作。

std::conjunction 确实需要 C++17,但您可以删除可变参数功能或使用 c++11/14 实现自己的 conjunction

template<template<class...> class tmpl, typename T>
struct _is_template_for : public std::false_type {};

template<template<class...> class tmpl, class... Args>
struct _is_template_for<tmpl, tmpl<Args...>> : public std::true_type {};

template<template<class...> class tmpl, typename... Ts>
using is_template_for = std::conjunction<_is_template_for<tmpl, std::decay_t<Ts>>...>;

template<template<class...> class tmpl, typename... Ts>
constexpr bool is_template_for_v = is_template_for<tmpl, Ts...>::value;

用法:

static_assert(is_template_for_v<std::vector, std::vector<int>>); // doesn't fire

【讨论】:

    【解决方案3】:

    正如别人写的,

    template<typename T, template<typename...> class TT>
    struct is_specialization_of : std::false_type { };
    
    template<template<typename...> class TT, typename... Ts>
    struct is_specialization_of<TT<Ts...>, TT> : std::true_type { };
    

    但是,请注意,这仅适用于模板类其模板参数都是类型名!

    typedef std::array<int, 42> MyArray;
    static_assert(is_specialization_of<MyArray, std::array>::value, "");
    

    它根本无法编译。

    相信C++11/C++14/C++17目前没有办法处理这个限制。

    【讨论】:

    • 这不是答案。复制/粘贴其他人的答案然后对其发表评论不是合适的答案。如果您对某人的回答有意见,请对他们的回答发表评论。
    • 谁是“别人”?请更新此答案以向您复制此代码的任何人提供正确的attribution。是Xeo's answer here,还是其他答案?
    • 欢迎来到2017,你们两个! :) 如果您愿意,可以随意将“其他人”编辑为“Andy Prowl”。
    猜你喜欢
    • 2011-01-14
    • 1970-01-01
    • 1970-01-01
    • 2020-10-31
    • 1970-01-01
    • 1970-01-01
    • 2014-11-05
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多