【发布时间】:2013-04-09 07:10:29
【问题描述】:
编辑,以避免混淆:
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_type 的省略号版本test。否则为T* 定义第一个方法并将返回std::true_type。实际的“切换”发生在第二个类中,它继承自 test 返回的类型。与 is_same 之类的不同方法相比,这似乎很聪明且“轻量级”。
带有两个参数的decltype 最初让我感到惊讶,因为我认为它只是获取表达式的类型。当我看到上面的代码时,我认为它类似于“尝试编译表达式并始终返回第二个的类型。如果表达式编译失败则失败”(所以隐藏这个专业化;SFINAE)。
但是:
然后我想我可以使用这种方法来编写任何“有效表达式”检查器,只要它依赖于某种类型T。示例:
...
template<class T>
static auto test(T* p) -> decltype(bar(*p), std::true_type());
...
我认为,当且仅当bar 定义为接受T 作为第一个参数(或者如果T 是可转换的,等等),这将返回std::true_type,即:如果bar(*p) 是在p 定义为T* 类型的上下文中编写的,则它会编译。
然而,上面的修改总是评估为std::false_type。 为什么会这样?我不想用一些复杂的不同代码来修复它。我只是想知道为什么它不能像我预期的那样工作。显然,带有两个参数的 decltype 的工作方式与我想象的不同。我找不到任何文件;处处只能用一种表达方式来解释。
【问题讨论】:
-
@Praetorian:天哪。我对这个问题感到困惑,现在有了你的评论,我知道为什么了。这太可怕了。整洁。
-
@Praetorian 这太容易了。如果您只使用其他人编写的代码,就会发生这种情况...... ;)
标签: c++ c++11 sfinae typetraits decltype