【发布时间】:2021-12-24 16:42:00
【问题描述】:
我遇到了与嵌套类方法的返回类型推导有关的问题。经过一番挖掘,我将问题缩小到简化版本如下:
#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)
}
struct is_alive 检查一个类是否有 operator() 使用函数重载技巧返回一个 Alive 实例。
如果没有第 (1) 行,则 (2) 处的 static_assert 返回 true 并且代码按预期编译。
但是,我不明白为什么添加第 (1) 行使第 (2) 行失败。好像我在盒子里看了看,不知何故杀死了猫。
所以这是我的问题:
- 为什么在第 (1) 行,
value是假的? - 为什么添加第 (1) 行使第 (2) 行失败?
如果您可以参考标准中规定该行为的部分,那就太好了。
【问题讨论】:
-
不知何故将
Cat::operator()的返回类型更改为Alive有效,但不知道原因。我的猜测是decltype(is_alive_impl<T>(0)无法推断出Alive,所以他们选择了返回void的另一个重载。 -
第 (1) 行使 (2) 失败,因为模板的不同实例化点在 ODR 方面必须一致(这样,编译器可以缓存实例化)。当存在分歧时,代码格式错误;无需诊断。至于分歧本身是否有效……高于我的工资等级。
-
@StoryTeller-UnslanderMonica 所以编译器在点 (1) 实例化 is_alive
并缓存结果以在点 (2) 重用?但是为什么在第 (1) 点,值是假的?我认为 Cat 类的定义是完整的,所以 value 应该是真的?谢谢。 -
@LanguageLawyer 我尝试了问题 (godbolt.org/z/GGc71Y7hs) 中的示例,编译器彼此不同意。所以这是解析问题的阶段?
标签: c++ templates language-lawyer