感謝decltype
作爲返回類型,C++ 11使得它非常容易引入裝飾器。例如,考慮這個類:爲什麼自動返回類型改變重載分辨率?
struct base
{
void fun(unsigned) {}
};
我想與額外的功能來裝飾它,因爲我會做多次與不同類型的裝飾品,我先介紹一個decorator
類,簡單地轉發一切base
。在真實代碼中,這是通過std::shared_ptr
完成的,以便我可以刪除裝飾並恢復「裸」對象,並且所有內容都是模板化的。
#include <utility> // std::forward
struct decorator
{
base b;
template <typename... Args>
auto
fun(Args&&... args)
-> decltype(b.fun(std::forward<Args>(args)...))
{
return b.fun(std::forward<Args>(args)...);
}
};
完美轉發和decltype
只是美好的。在真正的代碼中,我實際上使用了一個只需要函數名稱的宏,其餘都是樣板。
然後,我可以介紹一個derived
類添加功能我對象(derived
不當,表示同意,但它通過繼承有助於理解是derived
是-A-一種base
,儘管不是)。
struct foo_t {};
struct derived : decorator
{
using decorator::fun; // I want "native" fun, and decorated fun.
void fun(const foo_t&) {}
};
int main()
{
derived d;
d.fun(foo_t{});
}
然後C++ 14來了,與返回類型推演,讓寫的東西在一個簡單的方法:取出轉發功能的decltype
部分:
struct decorator
{
base b;
template <typename... Args>
auto
fun(Args&&... args)
{
return b.fun(std::forward<Args>(args)...);
}
};
而且然後它休息。是的,至少根據GCC和Clang的,這一點:
template <typename... Args>
auto
fun(Args&&... args)
-> decltype(b.fun(std::forward<Args>(args)...))
{
return b.fun(std::forward<Args>(args)...);
}
};
不等同於這個(和問題的關鍵不是auto
與decltype(auto)
):
template <typename... Args>
auto
fun(Args&&... args)
{
return b.fun(std::forward<Args>(args)...);
}
};
中的重載決策似乎是完全不同的,它最終是這樣的:
clang++-mp-3.5 -std=c++1y main.cc
main.cc:19:18: error: no viable conversion from 'foo_t' to 'unsigned int'
return b.fun(std::forward<Args>(args)...);
^~~~~~~~~~~~~~~~~~~~~~~~
main.cc:32:5: note: in instantiation of function template specialization
'decorator::fun<foo_t>' requested here
d.fun(foo_t{});
^
main.cc:7:20: note: passing argument to parameter here
void fun(unsigned) {}
^
我明白了失敗的原因:我的電話(d.fun(foo_t{})
)不簽名完全匹配的derived::fun
,這需要const foo_t&
,所以非常渴望decorator::fun
踢(我們知道Args&&...
是如何綁定到任何不完美匹配的極其不耐煩)。所以它將此轉發給base::fun
,這不能處理foo_t
。
如果我改變derived::fun
採取的foo_t
代替const foo_t&
,那麼它將按預期工作,這表明確實是這裏的問題是,有derived::fun
和decorator::fun
之間的競爭。
然而,爲什麼這個表演與返回式扣除?更準確地說,爲什麼是委員會選擇的這種行爲?
爲了方便起見,在Coliru:
謝謝!
@Nawaz:謝謝你的提示。在這裏,它沒有任何區別。 – akim 2014-11-03 08:42:26
'decltype(b.fun(std :: forward(args)...))'在尾隨返回類型中* *表達式SFINAE *,而'auto'和'decltype(auto)'都不會 –
2014-11-03 08:42:43
要添加到Piotr S.的評論:這也是故意的。爲了使SFINAE正常工作,返回類型必須可用,而不必查看函數體。要啓用返回的lambda表達式,返回類型不能在不查看函數體的情況下可用。作出了一個決定,使返回的lambda比SFINAE更重要。 – hvd 2014-11-03 08:47:29