Edit, in order to avoid confusion:
decltype
does not accept two arguments. See answers.编辑,以避免混淆:decltype不接受两个参数。看到答案。
The following two structs can be used to check for the existance of a member function on a type T
during compile-time:
下面的两个结构可以用来检查在编译期间在类型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))
{};
I think the idea is to use SFINAE when checking for the existance of a member function, so in case p->foo()
isn't valid, only the ellipses version of test
, which returns the std::false_type
is defined. Otherwise the first method is defined for T*
and will return std::true_type
. The actual "switch" happens in the second class, which inherits from the type returned by test
. This seems clever and "lightweight" compared to different approaches with is_same
and stuff like that.
我认为这个想法是在检查成员函数的存在时使用SFINAE,因此,如果p->foo()不是有效的,只有测试的省略版本,它返回std::false_type。否则,将为T*定义第一个方法,并返回std::true_type。实际的“切换”发生在第二个类中,它继承了test返回的类型。与is_same之类的不同方法相比,这看起来更聪明,更“轻量级”。
The decltype
with two arguments first looked surprising to me, as I thought it just gets the type of an expression. When I saw the code above, I thought it's something like "try to compile the expressions and always return the type of the second. Fail if the expressions fail to compile" (so hide this specialization; SFINAE).
带有两个参数的解密首先让我感到惊讶,因为我认为它只是得到了一个表达式的类型。当我看到上面的代码时,我认为它是类似于“尝试编译表达式并总是返回第二个表达式的类型”。如果表达式编译失败,则失败”(因此隐藏这个专门化;SFINAE)。
But:
但是:
Then I thought I could use this method to write any "is valid expression" checker, as long as it depends on some type T
. Example:
然后我想我可以用这个方法来写任何“是有效的表达式”检查器,只要它依赖于某种类型的t。
...
template<class T>
static auto test(T* p) -> decltype(bar(*p), std::true_type());
...
http://ideone.com/dJkLPF
This, so I thought, will return a std::true_type
if and only if bar
is defined accepting a T
as the first parameter (or if T
is convertible, etc...), i.e.: if bar(*p)
would compile if it was written in some context where p
is defined of type T*
.
我想,这将返回一个std: true_type,当且仅当bar被定义为接受T作为第一个参数时(或者如果T是可转换的,等等…),例如。: if bar(*p)将被编译,如果它是在某个定义为T*类型的上下文中编写的。
However, the modification above evaluates always to std::false_type
. Why is this? I don't want to fix it with some complicated different code. I just want to know why it doesn't work as I expected it to. Clearly, decltype
with two arguments works different than I thought. I couldn't find any documentation; it's only explained with one expression everywhere.
但是,上面的修改总是计算为std::false。这是为什么呢?我不想用一些复杂的不同代码来修复它。我只是想知道为什么它不能像我期望的那样工作。显然,用两个论点来解密比我想象的要有效得多。我找不到任何文件;它在任何地方都只能用一个表达式来解释。
2 个解决方案
#1
28
It's an comma-separated list of expressions, the type is identical to the type of the last expression in the list. It's usually used to verify that the first expression is valid (compilable, think SFINAE), the second is used to specify that decltype
should return in case the first expression is valid.
它是一个逗号分隔的表达式列表,类型与列表中最后一个表达式的类型相同。它通常用于验证第一个表达式是有效的(可编译的,请考虑SFINAE),第二个用于指定如果第一个表达式是有效的,那么应该返回decltype。
#2
12
decltype
does not take two arguments. Simply, it can can have an expression as its argument, and the comma operator is one way of creating expressions. Per Paragraph 5.18/1:
decltype不接受两个参数。简单地说,它可以有一个表达式作为参数,逗号运算符是创建表达式的一种方式。每段5.18/1:
[...] A pair of expressions separated by a comma is evaluated left-to-right; the left expression is a discarded-value expression (Clause 5). Every value computation and side effect associated with the left expression is sequenced before every value computation and side effect associated with the right expression. The type and value of the result are the type and value of the right operand; the result is of the same value category as its right operand, and is a bit-field if its right operand is a glvalue and a bit-field. If the value of the right operand is a temporary (12.2), the result is that temporary.
[…用逗号分隔的一对表达式从左到右计算;左表达式是一个丢弃值表达式(第5条),与左表达式相关的每个值计算和副作用都在每个值计算和与右表达式相关的副作用之前进行排序。结果的类型和值是正确操作数的类型和值;结果与它的右操作数具有相同的值类别,如果它的右操作数是一个glvalue和一个bit字段,那么结果就是位字段。如果右操作数的值是临时的(12.2),那么结果就是临时的。
Therefore:
因此:
static_assert(std::is_same<decltype(42, 3.14), double>::value, "Will not fire");
#1
28
It's an comma-separated list of expressions, the type is identical to the type of the last expression in the list. It's usually used to verify that the first expression is valid (compilable, think SFINAE), the second is used to specify that decltype
should return in case the first expression is valid.
它是一个逗号分隔的表达式列表,类型与列表中最后一个表达式的类型相同。它通常用于验证第一个表达式是有效的(可编译的,请考虑SFINAE),第二个用于指定如果第一个表达式是有效的,那么应该返回decltype。
#2
12
decltype
does not take two arguments. Simply, it can can have an expression as its argument, and the comma operator is one way of creating expressions. Per Paragraph 5.18/1:
decltype不接受两个参数。简单地说,它可以有一个表达式作为参数,逗号运算符是创建表达式的一种方式。每段5.18/1:
[...] A pair of expressions separated by a comma is evaluated left-to-right; the left expression is a discarded-value expression (Clause 5). Every value computation and side effect associated with the left expression is sequenced before every value computation and side effect associated with the right expression. The type and value of the result are the type and value of the right operand; the result is of the same value category as its right operand, and is a bit-field if its right operand is a glvalue and a bit-field. If the value of the right operand is a temporary (12.2), the result is that temporary.
[…用逗号分隔的一对表达式从左到右计算;左表达式是一个丢弃值表达式(第5条),与左表达式相关的每个值计算和副作用都在每个值计算和与右表达式相关的副作用之前进行排序。结果的类型和值是正确操作数的类型和值;结果与它的右操作数具有相同的值类别,如果它的右操作数是一个glvalue和一个bit字段,那么结果就是位字段。如果右操作数的值是临时的(12.2),那么结果就是临时的。
Therefore:
因此:
static_assert(std::is_same<decltype(42, 3.14), double>::value, "Will not fire");