C++ class 模板构造函数 -- 用数组 (U*) 重载引用 (U&) 失败
C++ class template constructor -- overload reference(U&) with array(U*) failed
我正在尝试构建一个构造函数以将数组作为参数,该参数会重载另一个采用标量的参数。代码如下。
#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>
并将 U
替换为 T
。该程序运行良好。我应该怎么做才能纠正这个问题?
如有任何建议,我们将不胜感激!
以下是如何使用 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
}
尽管两个构造函数都使用显式说明符并尝试避免类型转换,但您应该注意第一个与第二个一样好。如果你用 U 代替 float* 你会得到:
显式 SmallVec(const float*& scalar)
完全可以接受,并且会解释编译错误。
您可以通过将第二个构造函数更改为:
来解决问题
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());
I am trying to build a constructor to take an array as an argument
(...)
explicit SmallVec(const U* vec) { // if a vector, copy one by one
你不带数组。你拿一个指针,它可能指向也可能不指向一个数组,即使它指向一个数组,谁说数组至少有三个元素?这是一个严重的设计缺陷。
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 个元素设置为有效值;其他两个元素保持未初始化状态,并且从未初始化的 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;
}
我正在尝试构建一个构造函数以将数组作为参数,该参数会重载另一个采用标量的参数。代码如下。
#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>
并将 U
替换为 T
。该程序运行良好。我应该怎么做才能纠正这个问题?
如有任何建议,我们将不胜感激!
以下是如何使用 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
}
尽管两个构造函数都使用显式说明符并尝试避免类型转换,但您应该注意第一个与第二个一样好。如果你用 U 代替 float* 你会得到:
显式 SmallVec(const float*& scalar)
完全可以接受,并且会解释编译错误。 您可以通过将第二个构造函数更改为:
来解决问题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());
I am trying to build a constructor to take an array as an argument
(...)
explicit SmallVec(const U* vec) { // if a vector, copy one by one
你不带数组。你拿一个指针,它可能指向也可能不指向一个数组,即使它指向一个数组,谁说数组至少有三个元素?这是一个严重的设计缺陷。
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 个元素设置为有效值;其他两个元素保持未初始化状态,并且从未初始化的 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;
}