编译时间模板实例化检查 [英] Compile time template instantiation check

查看:125
本文介绍了编译时间模板实例化检查的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

是否可以检查在编译时是否已实例化模板类型,以便我可以在enable_if专业化中使用此信息?

Is it possible to check if a template type has been instantiated at compile time so that I can use this information in an enable_if specialization?

假设我已经

template <typename T> struct known_type { };

如果在编译时实例化了known_type,我可以以某种方式定义其值为true的is_known_type吗?

Can I somehow define some is_known_type whose value is true if known_type is instantiated at compile time?

推荐答案

如果利用特定表达式可能会或可能不会在的地方使用的事实,则可以执行此操作constexpr 是必需的,您可以查询以查看每个候选人的状态。特别是在我们的案例中,没有定义的 constexpr s不能作为常量表达式传递,而 noexcept 的事实可以保证常量表达式。因此, noexcept(...)返回 true 表示存在正确定义的 constexpr

It's possible to do this if you leverage the fact that specific expressions may or may not be used in places where constexprs are expected, and that you can query to see what the state is for each candidate you have. Specifically in our case, the fact that constexprs with no definition cannot pass as constant expressions and noexcept is a guarantee of constant expressions. Hence, noexcept(...) returning true signals the presence of a properly defined constexpr.

本质上,这会将 constexpr s视为是/否开关,并引入了

Essentially, this treats constexprs as Yes/No switches, and introduces state at compile-time.

请注意,这几乎是一个hack,您将需要特定编译器的变通办法(请参见前面的文章)和特定的<$ c $基于c> friend 的实施可能会因将来对该标准的修订而被认为是错误的。

Note that this is pretty much a hack, you will need workarounds for specific compilers (see the articles ahead) and this specific friend-based implementation might be considered ill-formed by future revisions of the standard.

有了这种方式...

用户菲利普·罗森他的文章专门针对它。

他的示例实现是带有引号的解释:

His example implementation is, with quoted explanations:

constexpr int flag (int);




constexpr函数可以处于两种状态之一;是
可以在常量表达式中使用,还是不是-如果缺少
定义,它将自动属于后一种类别-没有
的其他状态(除非我们考虑

A constexpr function can be in either one of two states; either it is usable in a constant-expression, or it isn't - if it lacks a definition it automatically falls in the latter category - there is no other state (unless we consider undefined behavior).

通常,constexpr函数应与
完全相同;函数,但我们也可以将它们看作
变量的单独句柄,其类型类似于bool,其中每个变量可以
具有两个值之一;可用或不可用。

Normally, constexpr functions should be treated exactly as what they are; functions, but we can also think of them as individual handles to "variables" having a type similar to bool, where each "variable" can have one of two values; usable or not-usable.

在我们的程序中,如果您认为flag只是那样,将会有所帮助;句柄
(不是函数)。原因是我们永远不会在评估的上下文中真正调用标志
,我们只对它的当前状态感兴趣。

In our program it helps if you consider flag to be just that; a handle (not a function). The reason is that we will never actually call flag in an evaluated context, we are only interested in its current state.



template<class Tag>
struct writer {
  friend constexpr int flag (Tag) {
    return 0;
  }
};




writer是一个类模板,在实例化时将创建一个
在其周围命名空间中的功能定义(具有
签名int标志(标记),其中Tag是模板参数)。

writer is a class template which, upon instantiation, will create a definition for a function in its surrounding namespace (having the signature int flag (Tag), where Tag is a template-parameter).

如果我们再一次将constexpr函数视为
变量的句柄,我们可以将writer的实例视为

无条件写入,该变量可用于
函数后面的变量。

If we, once again, think of constexpr functions as handles to some variable, we can treat an instantiation of writer as an unconditional write of the value usable to the variable behind the function in the friend-declaration.



template<bool B, class Tag = int>
struct dependent_writer : writer<Tag> { };




如果您认为dependent_writer看起来像$ b,我不会感到惊讶$ b是毫无意义的间接调用;为什么不直接在我们要使用它的地方实例化写程序
,而不是通过dependent_writer?

I would not be surprised if you think dependent_writer looks like a rather pointless indirection; why not directly instantiate writer where we want to use it, instead of going through dependent_writer?


  1. 写程序的实例必须取决于防止立即实例化的东西;并且

  2. dependent_writer用于上下文类型为bool的值可以用作依赖项的情况。




template<
  bool B = noexcept (flag (0)),
  int    =   sizeof (dependent_writer<B>)
>
constexpr int f () {
  return B;
}




上面的内容可能有点怪异,但

The above might look a little weird, but it's really quite simple;


  1. 如果flag(0)是常量表达式,则将B设置为true,否则B =否,并且;

  2. 隐式实例化dependent_writer(sizeof需要一个完全定义的类型)。

可以用以下伪代码表示:

The behavior can be expressed with the following pseudo-code:

IF [ `int flag (int)` has not yet been defined ]:
  SET `B` =   `false`
  INSTANTIATE `dependent_writer<false>`
  RETURN      `false`
ELSE:
  SET `B` =   `true`
  INSTANTIATE `dependent_writer<true>`
  RETURN      `true`


最后是概念证明:

int main () {
  constexpr int a = f ();
  constexpr int b = f ();
  static_assert (a != b, "fail");
}






我将此应用于您特殊的问题。想法是使用 constexpr 是/否开关指示是否已实例化类型。因此,您将需要为每种类型单独设置一个开关。


I applied this to your particular problem. The idea is to use the constexpr Yes/No switches to indicate whether a type has been instantiated. So, you'll need a separate switch for every type you have.

template<typename T>
struct inst_check_wrapper
{
    friend constexpr int inst_flag(inst_check_wrapper<T>);
};

inst_check_wrapper< T> 本质上包装了一个开关无论您使用哪种类型。

inst_check_wrapper<T> essentially wraps a switch for whatever type you may give it. It's just a generic version of the original example.

template<typename T>
struct writer 
{
    friend constexpr int inst_flag(inst_check_wrapper<T>) 
    {
        return 0;
    }
};

开关切换器与原始示例中的相同。它附带了您使用的某种类型的开关的定义。为了便于检查,请添加辅助开关检查器:

The switch toggler is identical to the one in the original example. It comes up with the definition for the switch of some type that you use. To allow for easy checking, add a helper switch inspector:

template <typename T, bool B = noexcept(inst_flag(inst_check_wrapper<T>()))>
constexpr bool is_instantiated()
{
    return B;
}

最后,类型注册为已初始化。就我而言:

Finally, the type "registers" itself as initialized. In my case:

template <typename T>
struct MyStruct
{
    template <typename T1 = T, int = sizeof(writer<MyStruct<T1>>)>
    MyStruct()
    {}
};

请求特定的构造函数后,便立即打开该开关。示例:

The switch is turned on as soon as that particular constructor is asked for. Sample:

int main () 
{
    static_assert(!is_instantiated<MyStruct<int>>(), "failure");
    MyStruct<int> a;
    static_assert(is_instantiated<MyStruct<int>>(), "failure");
}

在Coliru上直播。

这篇关于编译时间模板实例化检查的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆