我來函式式編程有點晚了,并開始了解范圍/視圖。我正在使用 MSVC19 并為 C 20 編譯。
我正在使用std::views::transform并且編譯器似乎并沒有像我天真地希望的那樣推斷型別。
這是一個小例子,它只需要一個字串向量并計算它們的長度:
#include <vector>
#include <iostream>
#include <ranges>
template<typename E>
auto length(const E& s)
{
std::cout << "Templated length()\n";
return static_cast<int>(s.length());
}
template<typename E>
auto getLengths(const std::vector<E>& v)
{
return v | std::views::transform(length<E>);
}
int main()
{
std::vector<std::string> vec = { "Larry","Curly","Moe" };
for (int i : getLengths(vec))
{
std::cout << i << "\n";
}
return 0;
}
輸出:
Templated length()
5
Templated length()
5
Templated length()
3
我的問題是為什么要更改此行中的代碼(洗掉<E>):
return v | std::views::transform(length);
給我一大堆錯誤,從:Error C2672 'operator __surrogate_func': no matching overloaded function found?
為什么編譯器不推斷型別是std::string?如果我用非模板化函式替換模板:
auto length(const std::string& s) -> int
{
std::cout << "Specialized length()\n";
return static_cast<int>(s.length());
}
代碼編譯并運行,很明顯,沒有模板,編譯器會找到我正在使用的特定型別的匹配項。
uj5u.com熱心網友回復:
這與視圖無關。您可以將問題簡化為:
template <typename T>
int length(T const& x) { return x.length(); }
template <typename F>
void do_something(F&& f) {
// in theory use f to call something
}
void stuff() {
do_something(length); // error
}
C 并沒有真正進行型別推斷。當你有do_something(length),我們需要挑選哪些 length我們談論在那里。我們不能這樣做,所以這是一個錯誤。沒有辦法do_something說“我想要用 a 呼叫的函式模板的實體化std::string- 這完全取決于呼叫者提供do_something正確的東西。
在原始示例中也是如此。length<E>是一個具體的函式。length不是你可以隨便傳入的東西。
典型的方法是通過將函式模板包裝在 lambda 中來延遲實體化:
void stuff() {
do_something([](auto const& e) { return length(e); }); // ok
}
現在,這有效 - 因為 lambda 是一個運算式,它的型別可以由 推匯出do_something,而只是length不是。并且我們不必手動提供模板引數,這很容易出錯。
我們可以用一個宏來概括:
#define FWD(arg) static_cast<decltype(arg)&&>(arg)
#define LIFT(name) [&](auto&&... args) -> decltype(name(FWD(args)...)) { return name(FWD(args)...); }
void stuff() {
do_something(LIFT(length));
}
這避免了一些額外的輸入,并且可能使意圖更清晰一些。
轉載請註明出處,本文鏈接:https://www.uj5u.com/houduan/366258.html
