什么是带有两个参数的decltype?

时间:2013-04-16 18:31:57

标签: c++ c++11 sfinae typetraits decltype

  

编辑,以避免混淆: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

http://ideone.com/dJkLPF

我想,如果且仅当... 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有两个参数的工作方式与我想的不同。我找不到任何文件;它只能用一个表达式来解释。

2 个答案:

答案 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");