有两个参数的decltype是什么

What is decltype with two arguments?

本文关键字:参数 decltype 是什么 两个      更新时间:2023-10-16

编辑,为了避免混淆:decltype不接受两个参数。查看答案

以下两个结构可用于在编译时检查类型T上是否存在成员函数:

// Non-templated helper struct:
struct _test_has_foo {
    template<class T>
    static auto test(T* p) -> decltype(p->foo(), std::true_type());
    template<class>
    static auto test(...) -> std::false_type;
};
// Templated actual struct:
template<class T>
struct has_foo : decltype(_test_has_foo::test<T>(0))
{};

我认为这个想法是在检查成员函数的存在时使用SFINAE,所以在p->foo()无效的情况下,只定义返回std::false_typetest的省略号版本。否则,为T*定义第一个方法,并返回std::true_type。实际的"switch"发生在第二个类中,它继承了test返回的类型。与is_same之类的不同方法相比,这看起来既聪明又"轻量级"。

带有两个自变量的decltype首先让我感到惊讶,因为我认为它只是得到了表达式的类型。当我看到上面的代码时,我觉得这有点像"尝试编译表达式,并始终返回第二个表达式的类型。如果表达式编译失败,则失败"(所以隐藏这种专门化;SFINAE(。

但是:

然后我想我可以用这个方法来写任何"是有效的表达式"检查器,只要它依赖于某种类型的T。示例:

...
    template<class T>
    static auto test(T* p) -> decltype(bar(*p), std::true_type());
...

http://ideone.com/dJkLPF

因此,我认为,这将返回std::true_type,当且仅当bar被定义为接受T作为第一个参数(或者如果T是可转换的,等等(,即:如果bar(*p)是在p被定义为T*类型的上下文中编写的,则它将编译。

但是,上面的修改将始终计算为std::false_type为什么我不想用一些复杂的不同代码来修复它。我只是想知道为什么它没有像我预期的那样工作。很明显,带有两个参数的decltype的工作方式与我想象的不同。我找不到任何文件;到处都只能用一句话来解释。

这是一个逗号分隔的表达式列表,类型与列表中最后一个表达式的类型相同。它通常用于验证第一个表达式是否有效(compilable,想想SFINAE(,第二个用于指定在第一个表达式有效的情况下decltype应该返回。

decltype不接受两个参数。简单地说,它可以有一个表达式作为参数,逗号运算符是创建表达式的一种方法。根据第5.18/1:段

[…]由逗号分隔的一对表达式从左到右进行求值;左边的表达式是一个已丢弃的值表达(第5条(。与左表达式相关的每个值计算和副作用在每个值计算和与正确表达式相关联的副作用之前进行排序类型结果的值是右操作数的类型和值;结果属于相同的值类别如果其右操作数是glvalue和位字段,则为位字段。如果权利的价值操作数是临时的(12.2(,结果就是临时的。

因此:

static_assert(std::is_same<decltype(42, 3.14), double>::value, "Will not fire");