gpt4 book ai didi

c++ - 重载前模板实例化错误

转载 作者:太空狗 更新时间:2023-10-29 20:34:44 25 4
gpt4 key购买 nike

给定以下代码

#include <type_traits>
#include <utility>

template <typename T>
class Something {
public:
template <typename F>
auto foo(F&&)
-> decltype(std::declval<F>()(std::declval<T&>())) {}
template <typename F>
auto foo(F&&) const
-> decltype(std::declval<F>()(std::declval<const T&>())) {}
};

int main() {
auto something = Something<int>{};
something.foo([](auto& val) {
++val;
});
}

https://wandbox.org/permlink/j24Pe9qOXV0oHcA8

当我尝试编译它时,我收到错误消息说我不允许修改 main 中 lambda 中的常量值。这意味着模板都以某种方式在类中被实例化,这导致了一个硬错误,因为错误在 lambda 的主体中。

这方面的规则是什么?为什么重载解析会尝试实例化一个永远不会被调用的模板? const 永远不应该在这里被调用,那么它为什么要尝试完全实例化它呢?

然而奇怪的是,当我将定义更改为按 decltype(auto) 返回并添加代码以执行与尾随返回类型所建议的相同的事情时,我没有看到错误。表示模板没有完全实例化?

template <typename F>
decltype(auto) foo(F&& f) {
auto t = T{};
f(t);
}
template <typename F>
decltype(auto) foo(F&& f) const {
const auto t = T{};
f(t);
}

我猜编译器在实例化至少带有传递函数的签名之前不知道要调用哪个函数。但这并不能解释为什么 decltype(auto) 版本有效......

最佳答案

(很抱歉缺少正确的标准术语,正在处理中...)

当调用 something.foo 时,必须考虑所有可能的重载:

template <typename F>
auto foo(F&&)
-> decltype(std::declval<F>()(std::declval<T&>())) {}

template <typename F>
auto foo(F&&) const
-> decltype(std::declval<F>()(std::declval<const T&>())) {}

为了检查重载是否可行,编译器需要评估尾随的 decltype(...)。第一个 decltype 将在没有错误的情况下进行评估,并将评估为 void

第二个会导致错误,因为您正试图使用​​ const T& 调用 lambda。

由于 lambda 是不受约束的,因此在 lambda 的主体实例化期间会发生错误。发生这种情况是因为(默认情况下)lambda 使用自动返回类型推导,这需要实例化 lambda 的主体。

因此,不可行的重载将因此导致编译错误,而不是让 SFINAEd 退出。如果您按如下方式约束 lambda...

something.foo([](auto& val) -> decltype(++val, void()) {
++val;
});

...不会发生错误,因为过载将被 SFINAE 视为不可行。此外,您将能够检测 lambda 调用是否对特定类型有效(即 T 是否支持 operator++()?) 来自Something::foo.


当您将返回类型更改为 decltype(auto) 时,返回类型是从函数体中推导出来的。

template <typename F>
decltype(auto) foo(F&& f) {
auto t = T{};
f(t);
}

template <typename F>
decltype(auto) foo(F&& f) const {
const auto t = T{};
f(t);
}

由于您的something 实例是非const,非const 限定重载将在此处采用。如果您的 main 定义如下:

int main() {
const auto something = Something<int>{};
something.foo([](auto& val) {
++val;
});
}

即使使用 decltype(auto),您也会遇到同样的错误。

关于c++ - 重载前模板实例化错误,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/46690320/

25 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com