5

代わりにスカラーを取る別のものをオーバーロードする引数として配列を取るコンストラクタを構築しようとしています。コードは以下です。

#include <iostream>

template <typename T>
class SmallVec { // This is a 3 dimensional vector class template
public:
    T data[3] = {0}; // internal data of class
    template <typename U>
    explicit SmallVec(const U& scalar) { // if a scalar, copy it to each element in data
        for(auto &item : data) {
            item = static_cast<T>(scalar);
        }
    }
    template <typename U>
    explicit SmallVec(const U* vec) { // if a vector, copy one by one
        for(auto &item : data) {
            item = static_cast<T>(*vec); 
            vec++;
        }
    }
};

int main() {
    float num = 1.2;
    float *arr = new float[3];
    arr[2] = 3.4;
    SmallVec<float> vec1(num); // take num, which works fine
    SmallVec<float> vec2(arr); // !!!--- error happens this line ---!!!
    std::cout << vec1.data[2] << " "  << vec2.data[2] << std::endl;
    return 0;
}

コンパイラは不平を言う

error: invalid static_cast from type 'float* const' to type 'float'

明らかに、vec2(arr)まだ最初のコンストラクターを呼び出します。ただし、削除template <typename U>してに置き換えるUT. プログラムは正常に動作します。これを修正するにはどうすればよいですか?

どんな提案でも大歓迎です!

4

3 に答える 3

3

SFINAE を使用して必要なものを取得する方法は次のとおりです。

#include <vector>
#include <map>
#include <string>

using namespace std;

template<class T>
  struct Foo {

    template <class U, typename enable_if<is_pointer<U>::value, int>::type = 0>
      Foo(U u){}

    template <class U, typename enable_if<!is_pointer<U>::value, int>::type = 0>
      Foo(U u){}

  };


int main()
{
  Foo<int> f('a'); // calls second constructor
  Foo<int> f2("a"); // calls first constructor
}

ライブ: https://godbolt.org/g/ZPcb5T

于 2016-04-24T07:48:46.700 に答える
2

引数として配列を取るコンストラクタを構築しようとしています

(...)

explicit SmallVec(const U* vec) { // if a vector, copy one by one

配列は取りません。arrayを指している場合と指していない場合がありますが、配列を指している場合でも、配列に少なくとも 3 つの要素があると誰が言いますか? それは重大な設計上の欠陥です。

C++ では、構文がひどいものであっても、参照または const 参照によって生の配列を取得できます。

explicit SmallVec(const U (&vec)[3]) {

コンストラクターの実装も異なります。

    for(int index = 0; index < 3; ++index) {
        data[index] = static_cast<T>(vec[index]); 
    }

しかし、を見るとmain、問題はさらに深刻です。new[]配列を動的に割り当てるために使用します。それはすでに非常に悪い考えです。偶然にも、あなたの例にもdelete[]. 代わりにローカル配列を使用しないのはなぜですか?

 float arr[3];

これにより、プログラムがコンパイルされ、おそらく正しく実行されますが、配列の 3 番目の要素のみを有効な値に設定しているため、コードには未定義の動作が残っています。他の 2 つの要素は初期化されていないままであり、初期化されていない から読み取ると、float単にコピーしたとしても、正式には未定義の動作になります。

だから、それを作るほうがいい:

 float arr[3] = { 0.0, 0.0, 3.4 };

それに加えて、C++11 では を使用するように勧められてstd::arrayいます。これにより、一般的に物事が少し安全になり、構文が改善されます。完全な例を次に示します。

#include <iostream>
#include <array>

template <typename T>
class SmallVec { // This is a 3 dimensional vector class template
public:
    std::array<T, 3> data; // internal data of class
    template <typename U>
    explicit SmallVec(const U& scalar) { // if a scalar, copy it to each element in data
        for(auto &item : data) {
            item = static_cast<T>(scalar);
        }
    }
    template <typename U>
    explicit SmallVec(std::array<U, 3> const& vec) { // if a vector, copy one by one
        for(int index = 0; index < 3; ++index) {
            data[index] = static_cast<T>(vec[index]); 
        }
    }
};

int main() {
    float num = 1.2;
    std::array<float, 3> arr = { 0.0, 0.0, 3.4 };
    SmallVec<float> vec1(num);
    SmallVec<float> vec2(arr);
    std::cout << vec1.data[2] << " "  << vec2.data[2] << std::endl;
    return 0;
}
于 2016-04-24T10:52:28.743 に答える
1

どちらのコンストラクターも明示的な指定子を使用し、型変換を回避しようとしますが、最初のコンストラクターは 2 番目のコンストラクターと同じくらい適切な候補であることに注意してください。U を float* に置き換えると、次のようになります。

明示的な SmallVec(const float*& scalar)

これは完全に受け入れられ、コンパイルエラーを説明します。2 番目のコンストラクターを次のように変更することで、問題を解決できます。

template <typename U>
explicit SmallVec(U* const vec) { // if a vector, copy one by one
    U* local = vec;
    for(auto &item : data) {
        item = static_cast<T>(*local);
        local++;
    }
}

ただし、さらに明確な方法をお勧めします。

class ScalarCopy {};
class VectorCopy {};

...

template <typename U>
SmallVec(const U& vec, ScalarCopy);

template <typename U>
SmallVec(const U* const vec, VectorCopy); 

そして明示的な呼び出しを行います:

SmallVec<float> vec1(num, ScalarCopy());
SmallVec<float> vec2(arr, VectorCopy());
于 2016-04-24T08:17:27.380 に答える