c++ - 编译时模板实例化检查

标签 c++ templates c++11 typetraits

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

假设我有

template <typename T> struct known_type { };

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

最佳答案

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

本质上,这对待 constexpr s 作为是/否开关,并在编译时引入状态。

请注意,这几乎是一个 hack,您将需要针对特定​​编译器的解决方法(请参阅前面的文章)和这个特定的 friend基于 -based 的实现可能会被标准的 future 修订视为格式错误。

有了这个……

用户 Filip Roséenhis article 中提出了这个概念专门致力于它。

他的示例实现是,引用了解释:

constexpr int flag (int);

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

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.

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

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> { };

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. Instantiation of writer must depend on something to prevent immediate instantiation, and;
  2. dependent_writer is used in a context where a value of type bool can be used as dependency.
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. will set B = true if flag(0) is a constant-expression, otherwise B = false, and;
  2. implicitly instantiates dependent_writer (sizeof requires a completely-defined type).

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是/否切换以指示类型是否已实例化。因此,对于您拥有的每种类型,您都需要一个单独的开关。

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

inst_check_wrapper<T>本质上为您可能提供的任何类型包装一个开关。它只是原始示例的通用版本。

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

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

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

最后,类型将自身“注册”为已初始化。就我而言:

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

一旦请求特定的构造函数,开关就会打开。示例:

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

Live on Coliru.

关于c++ - 编译时模板实例化检查,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/28179835/

相关文章:

c++ - "undefined reference to ` QString::fromAscii_helper(char const*, int) '"

具有动态回调函数类型的 C++ 模板类

java - Velocity 中已弃用的属性

c++ - 解压函数调用的参数数组

c++ - C++ 是否仍被视为静态类型语言?

c# - 如何将 .h 文件 +dll 变成某种 .Net 包装器?

c++ - 如何在 C++ 中创建对齐的整数数组?

c++ - 辅助函数应该放在头文件中还是放在实现文件中?

c++ - 参数包和成员函数指针类型推导

c++ - 有没有办法让 C++ 类在开始执行析构函数之前自动执行一个方法?