mib*_*ibu 9 c++ templates language-lawyer
我遇到了与嵌套类方法的返回类型推导相关的问题。经过一番挖掘,我将问题缩小到简化版本,如下所示:
#include <type_traits>
struct Alive {};
template<typename T>
auto is_alive_impl(...) -> void;
template<typename T>
auto is_alive_impl(int) -> decltype(std::declval<T>().operator()());
template<typename T>
struct is_alive : std::is_same<decltype(is_alive_impl<T>(0)), Alive> {};
struct Box {
struct Cat {
auto
operator()() {
return Alive{};
}
};
static constexpr auto value = is_alive<Cat>::value; // (1)
};
int main() {
static_assert(is_alive<Box::Cat>::value); // (2)
}
Run Code Online (Sandbox Code Playgroud)
struct is_alive使用函数重载技巧检查一个类是否operator()返回一个Alive实例。
如果没有第 (1) 行,则static_assertat (2) 返回true并且代码按预期进行编译。
但是,我不明白为什么添加第 (1) 行会使第 (2) 行失败。好像我看着盒子并不知何故杀死了那只猫。
这是我的问题:
value值为 false?如果您可以参考标准中规定该行为的部分内容,那就太好了。
您或多或少在 SFINAE 上下文中运行所有代码,因此您看不到任何问题。如果您只是尝试通过以下方式实例化您的类
int main() { Box::Cat bc; }
Run Code Online (Sandbox Code Playgroud)
我们看到所有的错误消息。
会发生什么:
如果您想在类内部定义(而不仅仅是声明!)一个需要推导返回类型的变量,则operator()该语句将失败,因为auto在定义类之前无法推导。(在带有右括号的类定义末尾。)这也会导致失败,std::declval<T>()因为它将auto value = is_alive<Cat>::value不起作用。由于我们处于 SFINAE 上下文中并且替换默默失败,因此我们在默认模板中运行 auto is_alive_impl(...) -> void;。嘭嘭:-)
如果我们添加更多的间接性并将猫放入一个较小的盒子中,我们可以运行代码:
struct LittleBox
{
struct Cat {
auto
operator()() {
return Alive{};
}
};
};
struct Box: public LittleBox {
static constexpr auto value = is_alive<Cat>::value; // (1)
};
Run Code Online (Sandbox Code Playgroud)
好的,更简单的是,我们可以定义 的返回类型operator()(),但不要auto在这里使用。
修复或解决方法似乎适用于 gcc/msvc/clang:探索