考慮下面的代碼錯誤模板實例超載
#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
當我嘗試編譯此我得到的錯誤,說不準我在修改的拉姆達一個const值之前主要。這意味着模板在某種程度上都是在類中實例化的,並且由於錯誤出現在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(自動)版本的作品...
「*實例化過程中會出現錯誤*」而不是何時?替代是自己的一步? –
@RyanHaining:在替換步驟中,'decltype(...)'尾隨返回類型實例化lambda的body ...導致錯誤。 –
這裏有什麼建議避免這個問題的方法?只需切換到'decltype(auto)'?我希望'foo'函數對於返回類型是SFINAE友好的,並且還有用戶代碼工作 – Curious