48407


以下のコードなのですがtemplateの方の関数で`return sunto<n - 1>();`とありますがそれは`tempalte<int
n>`のほうの関数をまた使ってるのでしょうか。一方`template<>`のほうはどこで利用されるのでしょうか？`template<>`関数をコメントにすると`int
array3`のほうでエラーになります。
coutでいつ使われてるか確認しようとしましたがエラーになるので使えませんでした。名前が同じなので混乱しています、解説をお願いしたいです。

[code]

    template<int n> constexpr int sunto() {
        return n + sunto<n - 1>();
    }
    
    template<> constexpr int sunto<0>(){
        //cout << "template<>を使用\n";
        return 0;
    }
    
    int array3[sunto<3>()];
    
    int main() {
        size_t t = sizeof(array3);
        for (size_t i = 0; i < t; i++) {
            cout << i<<'\n';
        }
        cout << t;
    
        _getch();
        return 0;
    }
    
[/code]


CC BY-SA 4.0
2018-09-14T12:00:59.867
48397
2018-09-14T16:50:58.250
2018-09-14T15:08:07.570
19110
question
c++
c++、同じ名前の関数でこの場合どっちが使われるのかわからない。


まず`template<> constexpr int sunto<0>()`がない場合のコンパイラの動きを確認してみます。

例えば  
`sunto<2>();`  
という式が現れた時、コンパイラはテンプレートのnに2を当てはめて、

[code]

    int sunto<2>() {
        return 2 + sunto<1>();
    }
    
[/code]

という関数を生成します(テンプレートの実体化)。生成した関数の中に`sunto<1>()`があるので、今度は

[code]

    int sunto<1>() {
        return 1 + sunto<0>();
    }
    
[/code]

を生成します。今度は`sunto<0>()`が出来たので、更に

[code]

    int sunto<0>() {
        return 0 + sunto<-1>();
    }
    
[/code]

を生成します。今度は`sunto<-1>()`が出来たので...  
という具合に、これはいつまでも無限に続きます。実際には無限に関数を生成することは不可能なので、いつかはメモリ不足か何かでコンパイルが失敗します。これが`template<>
constexpr int sunto<0>()`を消した時のエラーの理由です。

* * *

次に

[code]

    template<> constexpr int sunto<0>(){
        //cout << "template<>を使用\n";
        return 0;
    }
    
[/code]

があるときのコンパイラの動作を説明します。これはテンプレートの特殊化といい、`n==0`の時に限って、特別なコードを使うように指示するものです。前と同じように  
`sunto<2>();`  
を呼び出すと、`n==2`と`n==1`の時は、先ほどと同じですが、`n==0`の時に特殊化されたコードを生成します。つまり

[code]

    int sunto<2>() {
        return 2 + sunto<1>();
    }
    
    int sunto<1>() {
        return 1 + sunto<0>();
    }
    
    int sunto<0>(){
        //cout << "template<>を使用\n";
        return 0;
    }
    
[/code]

というコードが生成され、無事にコンパイルできるようになります。

* * *

ちなみに`template<> constexpr int
sunto<0>()`の中で`std::cout`を使うとエラーになるのは、`constexpr`がついているからです。`constexpr`がついていると、関数の結果はコンパイル時に決定しなければなりませんが、`std::cout`は実行時に値を出力するので、コンパイル時には呼び出せません。`constexpr`と矛盾してしまうのでエラーになります。

だからと言って、`constexpr`を取ってしまうと、`sunto<>()`自体の生成はうまくいきますが、今度は別のところ

`int array3[sunto<3>()];`

でエラーになってしまいます。配列のサイズは、コンパイル時に分かっていなければなりません。`sunto`に`constexpr`がついていれば、コンパイル時に計算結果が出せることが保証されるのでコンパイルが通りますが、ついていなければ保証がないのでエラーになります。


CC BY-SA 4.0
2018-09-14T16:50:58.250
48407
2018-09-14T16:50:58.250
3605
48397
answer