![](/img/trans.png)
[英]trailing return type using decltype with a variadic template function
[英]Specialize function template with decltype trailing return type
在C ++ 11中,如何使用decltype對使用“復雜”尾隨返回類型聲明的函數模板進行專門化處理? 以下內容在GCC中起作用,但在VC2013中產生“錯誤C2912:顯式專門化'int f(void)'不是功能模板的專門化”:
#include <iostream>
int myint() { return 1; }
template<class T>
auto f() -> decltype(myint()) // this seems to cause problems
{
std::cout << "general\n";
return 1;
}
template <>
auto f<double>() -> decltype(myint())
{
std::cout << "special\n";
return 2;
}
int main()
{
f<int>();
f<double>(); // compiler error in VC, but not in GCC
}
我說“復雜”的原因是缺少一個技術上准確的詞,因為我不確定是什么造成了差異。 例如,以下decltype使用不依賴於任何函數結果類型的內置操作,可以與模板專門化一起很好地工作:
自動f()-> decltype(1 +1)
因此,我的問題(彼此相關):
我的代碼是正確的C ++ 11嗎?
對我來說看起來正確。 同樣,用gcc和-Wall -Wextra
干凈地編譯clang。
這是VC錯誤嗎?
最有可能的。 VC在這方面是臭名昭著的,例如,Microsoft Visual C ++的兩階段模板實例化到底是什么? 或google msvc兩階段查找 。
如果這種專業化無法正常工作,我怎么能專門為不可更改的舊容器類專門設計std :: begin和std :: end(從而提供基於范圍的for循環)?
對於您提供的代碼,一種解決方法是使用typedef:
#include <iostream>
int myint() { return 1; }
typedef decltype(myint()) return_type;
template<class T>
return_type f()
{
std::cout << "general\n";
return 1;
}
template <>
return_type f<double>()
{
std::cout << "special\n";
return 2;
}
int main()
{
f<int>();
f<double>();
}
三個主流的編譯器(gcc,clang和vs)似乎都對此代碼感到滿意。
更新:
如果這種專業化無法正常工作,我怎么能專門為不可更改的舊容器類專門設計
std::begin
和std::end
(從而提供基於范圍的for循環)?
[並且從評論中:]我認為專門研究std::begin
和std::end
始終是最好的方法。
經過深思熟慮,專門的std::begin()
和std::end()
將是我的最后選擇。 我的第一個嘗試是提供成員begin()
和end()
函數; 不幸的是,這不是您的選擇,因為您無法修改相應的代碼。 然后,我的第二次嘗試是在自己的名稱空間中提供免費功能:
#include <iostream>
#include <initializer_list>
#include <vector>
namespace my_namespace {
template <typename T> class my_container;
template <typename T> T* begin(my_container<T>& c);
template <typename T> T* end(my_container<T>& c);
template <typename T>
class my_container {
public:
explicit my_container(std::initializer_list<T> list) : v(list) { }
friend T* begin<>(my_container& c);
friend T* end<>(my_container& c);
private:
std::vector<T> v;
};
template <typename T>
T* begin(my_container<T>& c) {
return c.v.data();
}
template <typename T>
T* end(my_container<T>& c) {
return c.v.data()+c.v.size();
}
}
int main() {
my_namespace::my_container<int> c{1, 2, 3};
for (int i : c)
std::cout << i << '\n';
}
如果您能夠將容器的std::begin()
和std::end()
專業化,則此方法必須有效。 如果您在全局名稱空間中執行此操作(即,您只需省略namespace my_namespace {
和namespace my_namespace {
}
)也可以使用,但是我更喜歡將實現放入我自己的名稱空間中。
也可以看看
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.