簡體   English   中英

使用decltype尾隨返回類型來專門化功能模板

[英]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)

因此,我的問題(彼此相關):

  1. 我的代碼是正確的C ++ 11嗎?
  2. 這是VC錯誤嗎?
  3. 如果這種專業化無法正常工作,我怎么能專門為不可更改的舊容器類專門設計std :: begin和std :: end(從而提供基於范圍的for循環)?

我的代碼是正確的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::beginstd::end (從而提供基於范圍的for循環)?
[並且從評論中:]我認為專門研究std::beginstd::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.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM