16

これは数週間前に機能していました:

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)

4

4 に答える 4

9

パラメータ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;
}

これで動作するはずです:オンラインデモ

于 2012-01-28T13:35:55.400 に答える
2

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'には3つのレベルがあります。

  1. template int parameter、または(non-VLA)arraysize//定数式でなければならないもの
  2. constexpr //定数式の可能性があるもの
  3. 非定数式

そのリストの下位にあるアイテムをそのリストの上位にあるものに実際に変換することはできませんが、明らかに他のルートで変換することは可能です。

たとえば、この関数の呼び出し

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定数式になります。

于 2012-01-28T14:05:59.533 に答える
2

質問を要約してください: type のパラメーターを取る 2 つの関数がありますT。1 つはそのパラメーターをテンプレート パラメーターとして受け取り、もう 1 つは「通常の」パラメーターとして受け取ります。funcTとのfuncN代わりにtfuncとの 2 つの関数を呼び出しますfuncfuncTから電話できるようにしたいと考えていますfuncN。後者を としてマークしconstexprても役に立ちません。

とマークされた関数は、あたかも存在しないconstexprかのようにコンパイル可能でなければなりませconstexprん。constexpr関数は少し統合失調症です。それらは、特定の状況でのみ完全な定数式に卒業します。

funcN を実行時に実行するように単純な方法で実装することはできません。これは、 tのすべての可能な値に対して機能する必要があるためです。これには、t の値ごとに 1 つずつ、多くの のインスタンスをインスタンス化する必要があります。ただし、T の小さなサブセットを使用する場合は、これを回避できます。g++ には 1024 のテンプレート再帰制限があるため、次のコードで T の 1024 値を簡単に処理できます。tfunc

#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これは、「通常の」パラメーター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);

}

これで template-recursion-limit を回避できると思いますが、それでも非常に多くのインスタンス化が必要であり、たとえ機能したとしてもコンパイルが非常に遅くなります。

于 2012-01-28T20:58:19.157 に答える
1

エラーが発生するように見えます-funcにtとして定数値を渡したことがわかりません。

より一般的には、ランタイム値をテンプレート引数として使用することはできません。テンプレートは本質的にコンパイル時の構成要素です。

于 2012-01-28T13:37:27.983 に答える