[英]C++11 constexpr function's argument passed in template argument
這曾經在幾周前工作:
template <typename T, T t>
T tfunc()
{
return t + 10;
}
template <typename T>
constexpr T func(T t)
{
return tfunc<T, t>();
}
int main()
{
std::cout << func(10) << std::endl;
return 0;
}
但是現在g++ -std=c++0x
說:
main.cpp: In function ‘constexpr T func(T) [with T = int]’:
main.cpp:29:25: instantiated from here
main.cpp:24:24: error: no matching function for call to ‘tfunc()’
main.cpp:24:24: note: candidate is:
main.cpp:16:14: note: template<class T, T t> T tfunc()
main.cpp:25:1: warning: control reaches end of non-void function [-Wreturn-type]
clang++ -std=c++11
表示模板的tfunc<T, t>()
被忽略,因為無效。
這是一個錯誤,還是修復?
PS:
g++ --version
=> g++ (GCC) 4.6.2 20120120 (prerelease)
clang++ --version
=> clang version 3.0 (tags/RELEASE_30/final)
(3.0.1)
參數t
不是常量表達式。 因此錯誤。 還應該指出,它不能是一個恆定的表達。
您可以將常量表達式作為參數傳遞,但在函數內部,保存該值的對象(參數)不是常量表達式。
由於t
不是常量表達式,因此不能用作模板參數:
return tfunc<T, t>(); //the second argument must be a constant expression
也許,你想要這樣的東西:
template <typename T, T t>
T tfunc()
{
return t + 10;
}
template <typename T, T t> //<---- t became template argument!
constexpr T func()
{
return tfunc<T, t>();
}
#define FUNC(a) func<decltype(a),a>()
int main()
{
std::cout << FUNC(10) << std::endl;
}
現在它應該工作: 在線演示
我覺得constexpr
也必須在'運行時'上下文中有效,而不僅僅是在編譯時。 將函數標記為constexpr
鼓勵編譯器嘗試在編譯時對其進行求值,但該函數仍必須具有有效的運行時實現。
實際上,這意味着編譯器不知道如何在運行時實現此函數:
template <typename T>
constexpr T func(T t)
{
return tfunc<T, t>();
}
解決方法是更改構造函數,使其將t
參數作為普通參數,而不是模板參數,並將構造函數標記為constexpr
:
template <typename T>
constexpr T tfunc(T t)
{
return t + 10;
}
template <typename T>
constexpr T func(T t)
{
return tfunc<T>(t);
}
有三個級別的'constant-expression-ness':
constexpr
// 可能是常量表達式的東西 您無法將該列表中較低的項目轉換為該列表中較高的項目,但顯然可能是其他路徑。
例如,調用此函數
constexpr int foo(int x) { return x+1; }
不一定是常數表達式。
// g++-4.6 used in these few lines. ideone doesn't like this code. I don't know why
int array[foo(3)]; // this is OK
int c = getchar();
int array[foo(c)]; // this will not compile (without VLAs)
因此, 只有在編譯時執行所有參數和函數的實現時, constexpr
函數的返回值才是常量表達式。
回顧一下問題:您有兩個函數,它們采用類型為T
的參數。 一個將其參數作為模板參數,另一個作為“正常”參數。 我將調用兩個函數funcT
和funcN
而不是tfunc
和func
。 你希望能夠調用funcT
從funcN
。 將后者標記為constexpr
並沒有幫助。
任何標記為constexpr
函數都必須是可編譯的,就好像constexpr
不在那里一樣。 constexpr
功能有點精神分裂。 在某些情況下,他們只能畢業於完全不變的表達。
不可能以簡單的方式實現funcN在運行時運行,因為它需要能夠為t的 所有可能值工作。 這將要求編譯器實例化tfunc
許多實例,每個t的值為一個。 但如果您願意使用T的一小部分,則可以解決這個問題。模板遞歸限制為1024(以g ++為單位),因此您可以使用以下代碼輕松處理1024的T值:
#include<iostream>
#include<functional>
#include<array>
using namespace std;
template <typename T, T t>
constexpr T funcT() {
return t + 10;
}
template<typename T, T u>
constexpr T worker (T t) {
return t==0 ? funcT<T,u>() : worker<T, u+1>(t-1);
}
template<>
constexpr int worker<int,1000> (int ) {
return -1;
}
template <typename T>
constexpr T funcN(T t)
{
return t<1000 ? worker<T,0>(t) : -1;
}
int main()
{
std::cout << funcN(10) << std::endl;
array<int, funcN(10)> a; // to verify that funcN(10) returns a constant-expression
return 0;
}
它使用一個函數worker
,它將'normal'參數t
遞歸轉換為模板參數u
,然后用它來實例化並執行tfunc<T,u>
。
關鍵的一行是return funcT<T,u>() : worker<T, u+1>(t-1);
這有局限性。 如果要使用long
或其他整數類型,則必須添加另一個專門化。 顯然,此代碼僅適用於0到1000之間的t - 確切的上限可能與編譯器有關。 另一種選擇可能是使用排序的二進制搜索,對於每個2的冪,使用不同的工作函數:
template<typename T, T u>
constexpr T worker4096 (T t) {
return t>=4096 ? worker2048<T, u+4096>(t-4096) : worker2048<T, u>(t);
}
我認為這將解決該模板遞歸限制,但它仍然需要非常大量的實例,並會使編譯速度很慢,如果在所有工作。
看起來它應該給出一個錯誤 - 它無法知道你傳入一個常量值作為t到func。
更一般地,您不能將運行時值用作模板參數。 模板本身就是一個編譯時構造。
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.