雖然我用這樣的代碼之前,並且很顯然,編譯器有足夠的信息來工作,我真的不明白爲什麼這個編譯:積分常數按價值傳遞,視爲constexpr?
template <class T, class I>
auto foo(const T& t, I i) {
return std::get<i>(t);
}
int main()
{
std::cerr << foo(std::make_tuple(3,4), std::integral_constant<std::size_t, 0>{});
return 0;
}
活生生的例子:http://coliru.stacked-crooked.com/a/fc9cc6b954912bc5。
似乎與gcc和clang一起工作。問題是,儘管integral_constant
將constexpr
轉換爲存儲的整數,但constexpr
成員函數隱式地將對象本身作爲參數,因此,除非我們正在調用成員函數本身的對象,否則這樣的函數不能用於constexpr
上下文中可以視爲constexpr
。
這裏,i
是傳遞給foo
的一個參數,因此i
肯定不能被當作constexpr
。然而,它是。一個更簡單的例子:
template <class I>
void foo(I i) {
constexpr std::size_t j = i;
}
這編譯過,只要std::integral_constant<std::size_t, 0>{}
傳遞給foo
。
我覺得我失去了明顯的constexpr
規則。是否有無狀態類型的例外或其他? (或者,也許是兩個主要編譯器中的編譯器錯誤?這段代碼似乎適用於clang 5和gcc 7.2)。
編輯:答案已發佈,但我認爲它不夠。特別是,鑑於foo
最後一個定義,爲什麼:
foo(std::integral_constant<std::size_t, 0>{});
編譯,而不是:
foo(0);
均爲0,且std::integral_constant<std::size_t, 0>{}
是常量表達式。
編輯2:它似乎歸結爲事實上,即使在不是常量表達式的對象上調用constexpr
成員函數,本身也可以被視爲常量表達式,只要this
未被使用。這很明顯。我不認爲這是很明顯的:
constexpr int foo(int x, int y) { return x; }
constexpr void bar(int y) { constexpr auto x = foo(0, y); }
這並不編譯,因爲y
作爲傳遞到foo
不是一個常量表達式。它沒有被使用並不重要。因此,只要this
未使用,完整的答案需要顯示標準中的某種語言,以證明成員函數可用作常量表達式,即使在非常量表達式對象上也是如此。
也適用於Visual C++:https://godbolt.org/g/Cknxco – Justin
似乎在英特爾編譯器上失敗:https://godbolt.org/g/wLc5dw – Justin
@Justin好趕上,雖然它是icc我打賭這是另一個無關的錯誤:-)。 –