编辑,以避免混淆:
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()
无效,只有test
的省略号版本,它返回{{ 1}}已定义。否则,第一个方法是为std::false_type
定义的,并将返回T*
。实际的“切换”发生在第二个类中,它继承自std::true_type
返回的类型。与使用test
等不同方法相比,这看起来更聪明,更轻巧。
带有两个参数的is_same
首先让我感到惊讶,因为我认为它只是获得表达式的类型。当我看到上面的代码时,我认为它类似于“尝试编译表达式并始终返回第二种类型。如果表达式无法编译则失败”(所以隐藏此专业化; SFINAE)。
可是:
然后我想我可以使用这种方法来编写任何“is valid expression”检查器,只要它依赖于某种类型decltype
。例如:
T
我想,如果且仅当...
template<class T>
static auto test(T* p) -> decltype(bar(*p), std::true_type());
...
被定义为接受std::true_type
作为第一个参数(或bar
可转换时),我认为这将返回T
, etc ...),即:如果T
是在bar(*p)
定义类型为p
的某些上下文中编写的话,则会编译。
但是,上述修改会将始终评估为T*
。 为什么会这样?我不想用一些复杂的不同代码修复它。我只是想知道为什么它不像我预期的那样工作。很明显, std::false_type
有两个参数的工作方式与我想的不同。我找不到任何文件;它只能用一个表达式来解释。
答案 0 :(得分:35)
这是一个以逗号分隔的表达式列表,其类型与列表中最后一个表达式的类型相同。它通常用于验证第一个表达式是否有效(可编译,想想SFINAE),第二个用于指定decltype
在第一个表达式有效时应该返回。
答案 1 :(得分:14)
decltype
没有两个参数。简单来说,它可以有一个表达式作为参数,逗号运算符是创建表达式的一种方式。根据第5.18 / 1段:
[...]用逗号分隔的一对表达式从左到右进行评估;左表达式是丢弃值 表达(第5条)。与左表达式相关的每个值计算和副作用 在每个值计算和与右表达式相关的副作用之前进行排序。 类型 和结果的值是右操作数的类型和值;结果具有相同的值类别 作为右操作数,如果右操作数是glvalue和bit-field,则是一个位字段。如果值合适 操作数是临时的(12.2),结果是暂时的。
因此:
static_assert(std::is_same<decltype(42, 3.14), double>::value, "Will not fire");