問題描述
我正在閱讀一些名為 C++11 和 C++14 概述,由 Leor Zolman 先生提出.在第 35 頁,他介紹了一種使用 decltype
進(jìn)行求和運(yùn)算的方法.
I'm reading some slides named An Overview of C++11 and C++14 presented by Mr. Leor Zolman. At Page 35 he introduces a way to do the sum operation with decltype
.
struct Sum {
template <typename T>
static T sum(T n) {
return n;
}
template <typename T, typename... Args>
/// static T sum(T n, Args... rest) {
static auto sum(T n, Args... rest) -> decltype(n + sum(rest...)) {
return n + sum(rest...);
}
};
當(dāng)為Sum::sum(1, 2.3, 4, 5);
使用這個(gè)片段時(shí),clang-3.6(from svn) 無法用 -std=c++ 編譯它11
/-std=c++1y
但 gcc-4.9 成功了.當(dāng)然,如果沒有對返回類型進(jìn)行類型推導(dǎo),兩者都可以編譯,但這涉及類型轉(zhuǎn)換,無法得到預(yù)期的結(jié)果.
When using this snippets forSum::sum(1, 2.3, 4, 5);
clang-3.6(from svn) fails to compile this with -std=c++11
/-std=c++1y
but gcc-4.9 succeeds. Of course without type deduction for the return type both compile, but that involves type conversion and cannot get the expected result.
那么這是否表示一個(gè) clang 錯(cuò)誤,或者是因?yàn)?gcc 擴(kuò)展(就 c++11 或 c++14 而言)?
So does this indicate a clang bug, or is because of a gcc extension(in respect of c++11 or c++14)?
推薦答案
Clang 的行為是正確的.這是一個(gè) GCC 錯(cuò)誤(并且演示文稿中的聲明也不正確).§3.3.2 [basic.scope.pdecl]/p1,6:
Clang's behavior is correct. This is a GCC bug (and the claim in the presentation is also incorrect). §3.3.2 [basic.scope.pdecl]/p1,6:
1 名稱的聲明點(diǎn)緊隨其后完整的聲明符(第 8 條)及其初始化程序(如果有)之前,除非如下所述.
1 The point of declaration for a name is immediately after its complete declarator (Clause 8) and before its initializer (if any), except as noted below.
6 類成員聲明點(diǎn)后,成員名可以在其類的范圍內(nèi)查找.
6 After the point of declaration of a class member, the member name can be looked up in the scope of its class.
第 3.3.7 節(jié) [basic.scope.class]/p1 說
And §3.3.7 [basic.scope.class]/p1 says
以下規(guī)則描述了在類中聲明的名稱的范圍.
The following rules describe the scope of names declared in classes.
1) 在類中聲明的名稱的潛在范圍不僅包括名稱聲明點(diǎn)之后的聲明區(qū)域,還有所有的函數(shù)體,默認(rèn)參數(shù),exception-specifications 和 brace-or-equal-initializers該類中的非靜態(tài)數(shù)據(jù)成員(包括嵌套類).
1) The potential scope of a name declared in a class consists not only of the declarative region following the name’s point of declaration, but also of all function bodies, default arguments, exception-specifications, and brace-or-equal-initializers of non-static data members in that class (including such things in nested classes).
trailing-return-types 不在該列表中.
尾隨返回類型是聲明符的一部分 (§8 [dcl.decl]/p4):
The trailing return type is part of the declarator (§8 [dcl.decl]/p4):
declarator:
ptr-declarator
noptr-declarator parameters-and-qualifiers trailing-return-type
因此 sum
的可變參數(shù)版本不在其自己的trailing-return-type 范圍內(nèi),并且無法通過名稱查找找到.
and so the variadic version of sum
isn't in scope within its own trailing-return-type and cannot be found by name lookup.
在 C++14 中,只需使用實(shí)際返回類型推導(dǎo)(并省略尾隨返回類型).在 C++11 中,你可以使用一個(gè)類模板和一個(gè)簡單轉(zhuǎn)發(fā)的函數(shù)模板:
In C++14, simply use actual return type deduction (and omit the trailing return type). In C++11, you may use a class template instead and a function template that simply forwards:
template<class T, class... Args>
struct Sum {
static auto sum(T n, Args... rest) -> decltype(n + Sum<Args...>::sum(rest...)) {
return n + Sum<Args...>::sum(rest...);
}
};
template<class T>
struct Sum<T>{
static T sum(T n) { return n; }
};
template<class T, class... Args>
auto sum(T n, Args... rest) -> decltype(Sum<T, Args...>::sum(n, rest...)){
return Sum<T, Args...>::sum(n, rest...);
}
這篇關(guān)于gcc 可以編譯可變參數(shù)模板,而 clang 不能的文章就介紹到這了,希望我們推薦的答案對大家有所幫助,也希望大家多多支持html5模板網(wǎng)!