簡體   English   中英

可變參數模板的聲明點

[英]Point of declaration for variadic template

可變參數模板在什么時候被視為“已聲明”? 這將在clang ++ 3.4下進行編譯,但不會在g ++ 4.8.2下進行編譯。

template <typename T>
const T &sum(const T &v) { return v; }

template <typename T, typename ... Ts>
auto sum(const T &v, const Ts & ... params) -> decltype(v + sum(params...));

template <typename T, typename ... Ts>
auto sum(const T &v, const Ts & ... params) -> decltype(v + sum(params...)) {
    return v + sum(params...);
}

int main() {
    sum(1, 2, 3);
}

顯然,g ++在尾隨返回類型中與函數本身不匹配。 來自g ++ 4.8.2的錯誤是:

sum.cpp: In function 'int main()':
sum.cpp:13:16: error: no matching function for call to 'sum(int, int, int)'
     sum(1, 2, 3);
                ^
sum.cpp:13:16: note: candidates are:
sum.cpp:2:10: note: template<class T> const T& sum(const T&)
 const T &sum(const T &v) { return v; }
          ^
sum.cpp:2:10: note:   template argument deduction/substitution failed:
sum.cpp:13:16: note:   candidate expects 1 argument, 3 provided
     sum(1, 2, 3);
                ^
sum.cpp:8:6: note: template<class T, class ... Ts> decltype ((v + sum(sum::params ...))) sum(const T&, const Ts& ...)
 auto sum(const T &v, const Ts & ... params) -> decltype(v + sum(params...)) {
      ^
sum.cpp:8:6: note:   template argument deduction/substitution failed:
sum.cpp: In substitution of 'template<class T, class ... Ts> decltype ((v + sum(sum::params ...))) sum(const T&, const Ts& ...) [with T = int; Ts = {int, int}]':
sum.cpp:13:16:   required from here
sum.cpp:5:74: error: no matching function for call to 'sum(const int&, const int&)'
 auto sum(const T &v, const Ts & ... params) -> decltype(v + sum(params...));
                                                                          ^
sum.cpp:5:74: note: candidate is:
sum.cpp:2:10: note: template<class T> const T& sum(const T&)
 const T &sum(const T &v) { return v; }
          ^
sum.cpp:2:10: note:   template argument deduction/substitution failed:
sum.cpp:5:74: note:   candidate expects 1 argument, 2 provided
 auto sum(const T &v, const Ts & ... params) -> decltype(v + sum(params...));
                                                                      ^

附錄:如果我刪除可變參數模板的聲明,則clang ++和g ++都會出錯。

附加2:我看到之前也曾問過類似的問題。 我想這里的真正問題是為什么它與一個編譯器一起工作而不與另一個編譯器一起工作。 另外,我可以通過使用非原始參數sum()在POI上強制ADL使其與g ++一起使用。

附錄3:在clang ++和g ++下都可以使用:

class A {
};
A operator+(const A &, const A &) {
    return A();
}

template <typename T>
const T &sum(const T &v) { return v; }

/*
template <typename T, typename ... Ts>
auto sum(const T &v, const Ts & ... params) -> decltype(v + sum(params...));
*/

template <typename T, typename ... Ts>
auto sum(const T &v, const Ts & ... params) -> decltype(v + sum(params...)) {
    return v + sum(params...);
}

int main() {
    //sum(1, 2, 3);
    sum(A(), A(), A());
}

正如這個問題的答案 (由Praetorian提供)表明,聲明僅在返回類型之后才完整,並且GCC是正確的。 我相信clang的行為也是允許的,但它不是可移植的。 鏈接中的答案提供了使用traits類的解決方法,通常可以完成該工作,但是它有些笨拙,並且容易出錯(因為您必須在單獨的表達式中構造return類型,這可能與函數有細微的區別)表達)。 另一個可能的解決方法是使函數成為類模板的靜態成員(然后添加轉發到靜態模板成員的自由函數)。

您可以考慮另一種解決方法,這在第二個示例中都得到了提示,該示例在兩個編譯器上均有效。 A上調用sum()時,您將應用用戶定義的類型作為參數。 這涉及依賴於參數的查找,這導致模板生成第二次查找A的名稱空間(恰好是全局名稱空間,與sum()相同sum()sum()重載,並且允許它在實例化過程中查找可變參數函數模板。

因此,如果您可以將其中一個參數始終設置為需要ADL的用戶定義類型,則可以在完全聲明可變參數模板之后依靠重載解析的第二階段來查找可變參數模板。 因此,也許這樣的事情可能滿足您的需求:

namespace sum_impl {
    struct Dummy { };

    template <typename T>
    T const &sum_helper(Dummy, T const &v) { return v; }

    template <typename T, typename ... Ts>
    auto sum_helper(Dummy d, T const &v, Ts const &...params)
            -> decltype(v + sum_helper(d, params...)) {
        return v + sum_helper(d, params...);
    }

    template<typename... P>
    auto sum( P const &...p )
            -> decltype( sum_helper( Dummy{}, p... ) {
        return sum_helper( Dummy{}, p... );
    }
}
using sum_impl::sum;

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

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