tuc*_*cio 10 c++ templates type-traits c++11
是否可以检查模板类型是否已在编译时实例化,以便我可以在enable_if特化中使用此信息?
让我说我有
template <typename T> struct known_type { };
Run Code Online (Sandbox Code Playgroud)
如果在编译时实例化known_type,我可以以某种方式定义一些is_known_type,其值为true吗?
小智 16
如果您利用特定表达式可能会或可能不会在需要constexprs的位置使用这一事实,并且您可以查询以查看您拥有的每个候选人的状态,则可以执行此操作.特别是在我们的例子中,constexpr没有定义的s不能作为常量表达式传递,并且noexcept是常量表达式的保证.因此,noexcept(...)返回true信号表示存在正确定义的信号constexpr.
本质上,这将constexprs视为是/否切换,并在编译时引入状态.
请注意,这几乎是一个黑客攻击,您将需要特定编译器的变通方法(请参阅前面的文章),并且这个friend基于特定的实现可能会被未来的标准版本视为格式错误.
随着那个...
用户FilipRoséen在他专门针对它的文章中提出了这个概念.
他的示例实现是引用的解释:
constexpr int flag (int);
Run Code Online (Sandbox Code Playgroud)
constexpr函数可以处于两种状态之一; 要么它可以在常量表达式中使用,要么它不是 - 如果它缺少定义它会自动落入后一类 - 没有其他状态(除非我们考虑未定义的行为).
通常,constexpr函数应该完全按照它们的原样处理; 函数,但我们也可以将它们视为具有类似bool类型的"变量"的单独句柄,其中每个"变量"可以具有两个值中的一个; 可用或不可用.
在我们的程序中,如果你认为旗帜就是这样,它会有所帮助; 句柄(不是函数).原因是我们永远不会在评估的上下文中实际调用flag,我们只对其当前状态感兴趣.
template<class Tag>
struct writer {
friend constexpr int flag (Tag) {
return 0;
}
};
Run Code Online (Sandbox Code Playgroud)
writer是一个类模板,在实例化时,将在其周围的命名空间中创建函数的定义(具有签名int标志(Tag),其中Tag是模板参数).
如果我们再次将constexpr函数视为某个变量的句柄,我们可以将writer的实例化视为无条件写入可用于friend-declaration中函数后面的变量的值.
template<bool B, class Tag = int>
struct dependent_writer : writer<Tag> { };
Run Code Online (Sandbox Code Playgroud)
如果你认为dependent_writer看起来像一个毫无意义的间接,我不会感到惊讶; 为什么不直接实例化我们想要使用它的编写器,而不是通过dependent_writer?
- 编写器的实例化必须依赖于某些东西以防止立即实例化,并且;
- dependent_writer用于bool类型的值可用作依赖项的上下文中.
template<
bool B = noexcept (flag (0)),
int = sizeof (dependent_writer<B>)
>
constexpr int f () {
return B;
}
Run Code Online (Sandbox Code Playgroud)
上面可能看起来有点奇怪,但它真的很简单;
- 如果flag(0)是常量表达式,则设置B = true,否则B = false,并且;
- 隐式实例化dependent_writer(sizeof需要完全定义的类型).
行为可以用以下伪代码表示:
Run Code Online (Sandbox Code Playgroud)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");
}
Run Code Online (Sandbox Code Playgroud)
我将此应用于您的特定问题.我们的想法是使用constexprYes/No开关来指示是否已实例化类型.因此,您需要为您拥有的每种类型提供单独的开关.
template<typename T>
struct inst_check_wrapper
{
friend constexpr int inst_flag(inst_check_wrapper<T>);
};
Run Code Online (Sandbox Code Playgroud)
inst_check_wrapper<T>基本上包装一个开关,你可以给它任何类型.它只是原始示例的通用版本.
template<typename T>
struct writer
{
friend constexpr int inst_flag(inst_check_wrapper<T>)
{
return 0;
}
};
Run Code Online (Sandbox Code Playgroud)
切换切换器与原始示例中的切换切换器相同.它提供了您使用的某种类型的开关的定义.为了便于检查,添加辅助开关检查器:
template <typename T, bool B = noexcept(inst_flag(inst_check_wrapper<T>()))>
constexpr bool is_instantiated()
{
return B;
}
Run Code Online (Sandbox Code Playgroud)
最后,类型"注册"自身为初始化.就我而言:
template <typename T>
struct MyStruct
{
template <typename T1 = T, int = sizeof(writer<MyStruct<T1>>)>
MyStruct()
{}
};
Run Code Online (Sandbox Code Playgroud)
一旦要求特定的构造函数,就会打开该开关.样品:
int main ()
{
static_assert(!is_instantiated<MyStruct<int>>(), "failure");
MyStruct<int> a;
static_assert(is_instantiated<MyStruct<int>>(), "failure");
}
Run Code Online (Sandbox Code Playgroud)
| 归档时间: |
|
| 查看次数: |
2942 次 |
| 最近记录: |