2017-06-16 18 views
1

で - http://www.learncpp.com/cpp-tutorial/132-function-template-instances/関数テンプレート値によって参照差

// passing all parameters by references 
template <typename T1, typename T2> 
const T2& add_two_objects(const T1& x,const T2& y) { 
     return x+y; 
}; 

int main() { 
    using std::cout; 
    int x(0),y(0); 
    std::cout << "Please enter number 1" << std::endl; 
    std::cin >> x; 
    std::cout << "Please enter number 2" << std::endl; 
    std::cin >> y; 
    cout<< "sum of two integers is " << add_two_objects(x,y+1.2) << '\n'; 
    cout<< "sum of two double is " << add_two_objects(x,y+2.52424324) << '\n'; 
    return 0; 
} 

プログラムは罰金コンパイルするが、実行時に、私はいつもセグメンテーションフォールトを取得します。しかし、値を渡すようにテンプレートを変更すると、すべてが機能します。

// passing all parameters by value 
template <typename T1, typename T2> 
const T2 add_two_objects(const T1 x,const T2 y) { 
     return x+y; 
}; 

誰でも説明していただけますか?

+2

のように見えるかもしれません。しかし、これはかなり無意味なコードであり、あまり書かれていません。別のチュートリアルを見つけるべきでしょうか? –

+0

@CodyGray少なくともturialは 'using namespace std;'の代わりに 'std :: cout'を使用しています – user463035818

+0

私はチュートリアルの例を改良して複雑なものを試しました(もちろん理解しています)。 – infoclogged

答えて

6

この

template <typename T1, typename T2> 
const T2& add_two_objects(const T1& x, const T2& y) { 
     return x+y; 
}; 

は一時的に参照を返します。戻り値を

template <typename T1, typename T2> 
T2 add_two_objects(const T1& x, const T2& y) { 
     return x+y; 
}; 

としてください。

Btw、ここではT2を返すことが最善のことです。例えば、T1=size_tT2=charの場合を考えてみましょう。より良い操作x+yが実際に

template <typename T1, typename T2> 
auto add_two_objects(const T1& x, const T2& y) 
-> decltype(x+y) 
{ 
    return x+y; 
}; 

を生成するタイプを戻す------編集-----

あなたは一時オブジェクトへの参照を返してはいけません。それはバグです。あなたがバグを望むなら、それを求めてください。また、貧弱なチュートリアルは使用しないでください。参照を返す必要がある/返さなければならない状況がありますが、これはその1つではありません。これらは、(すべての自動変数と一時変数がそうであるように)関数から返されるときに破棄されない(または範囲外になる)オブジェクトへの参照です。

+0

ですが、私はあなたの最初の解決策が示唆するような値ではなく参照を返したいと思います。チュートリアルコードが間違っているということですか? – infoclogged

+0

@infocloggedあなたは何への参照を返すのですか?メソッドの範囲内の変数への参照は、メソッドの範囲外では役に立たない。 – user463035818

+0

さて、私は今理解している。静的オブジェクトをインスタンス化すると、参照はもはや一時オブジェクトを指していません。したがって、(x + y)を返す代わりに、関数テンプレートに静的変数(静的T2 z;)を宣言してから、参照(z = x + y; return z;)を返すことができます。もちろん、これは実際のコードではなく、基本を理解することです。 – infoclogged

1

より明確にするために、整数を構造体に囲みましょう。すべてのコンパイラのここ

が実証プログラムがその出力を

prog.cc:22:18: warning: returning reference to temporary [-Wreturn-local-addr] 
     return x+y; 
       ^
sum of two integers is [A::~A() is called for x = 3] 
Segmentation fault 

ように見えるかもしれません

#include <iostream> 

struct A 
{ 
    A(int x) : x(x) {} 
    ~A() { std::cout << "[A::~A() is called for x = " << x << ']' << std::endl; } 
    int x; 
}; 

A operator +(const A &lhs, const A &rhs) 
{ 
    return A(lhs.x + rhs.x); 
} 

std::ostream & operator <<(std::ostream &os, const A &a) 
{ 
    return os << a.x; 
} 

template <typename T1, typename T2> 
const T2& add_two_objects(const T1& x,const T2& y) { 
     return x+y; 
}; 

int main() 
{ 
    std::cout<< "sum of two integers is " << add_two_objects(A(1), A(2)) << '\n'; 

    return 0; 
} 

ある最初の関数は、一時的な値への参照を返すことを警告しています。つまり、一時オブジェクトが破棄され、この出力が終了すると、この出力は

[A::~A() is called for x = 3] 

となります。

この結果、参照は無効になり、プログラムには未定義の動作が発生します。

実際には、あなたは、プログラムロジックに

int main() 
{ 
    const A &r = add_two_objects(A(1), A(2)); 
    std::cout<< "sum of two integers is " << r << '\n'; 

    return 0; 
} 

その出力は、上記のプログラムの参照が無効になっている

prog.cc:22:18: warning: returning reference to temporary [-Wreturn-local-addr] 
     return x+y; 
       ^
[A::~A() is called for x = 3] 
[A::~A() is called for x = 1] 
[A::~A() is called for x = 2] 
Segmentation fault 

とほぼ似ています以下の方法を想像することができます。

関数宣言

template <typename T1, typename T2> 
const T2/*&*/ add_two_objects(const T1& x,const T2& y) { 
     return x+y; 
}; 

の参照を削除する場合は、プログラムの出力は、あなたが一時的に参照を返すことはできません

sum of two integers is 3 
[A::~A() is called for x = 3] 
[A::~A() is called for x = 1] 
[A::~A() is called for x = 2] 
+0

構造体には警告がありますが、 'int'sには警告されない特別な理由はありますか? – user463035818

+0

@ tobi303構造体にコンストラクタとデストラクタがあることが理由です。 –

関連する問題