看看我的代码。它会将Vector4转换为Vector4。 有这个复制构造函数,它自动按组件执行转换组件。我无法理解一件事:为什么在构造结束时,当正确设置每个组件时,在每个组件上调用默认构造函数,使输出向量为空。您可以在下面的输出中看到执行流程。有趣的是,如果我用4个赋值替换初始化列表,代码就会按预期工作。
编译器是VS2013。
#include <cstdio>
using namespace std;
struct half
{
unsigned short data;
half() : data(0) { printf("half::default_constructor\n"); }
half(half& pattern) : data(pattern.data) { printf("half::copy_constructor\n"); }
explicit half(float pattern) : data(16) { printf("half::from_float_constructor\n"); }
operator float() { printf("half::to_float_operator\n"); return 3.0f; }
};
template <typename T>
struct Vector4
{
Vector4() : x(0), y(0), z(0), w(0) { }
Vector4(T value) : x(value), y(value), z(value), w(value) { }
Vector4(T x, T y, T z, T w) : x(x), y(y), z(z), w(w) { }
template <typename U>
Vector4(Vector4<U>& other) : x((T)other.x), y((T)other.y), z((T)other.z), w((T)other.w) { }
union
{
struct { T x, y, z, w; };
struct { T r, g, b, a; };
};
};
int main()
{
Vector4<float> a(0, 1, 4, 6);
Vector4<half> b(a);
}
该计划的输出:
half::from_float_constructor
half::to_float_operator
half::from_float_constructor
half::from_float_constructor
half::to_float_operator
half::from_float_constructor
half::from_float_constructor
half::to_float_operator
half::from_float_constructor
half::from_float_constructor
half::to_float_operator
half::from_float_constructor
half::default_constructor
half::default_constructor
half::default_constructor
half::default_constructor
答案 0 :(得分:4)
原因是代码无效。您不能在联合中存储非POD类型。您的代码会导致未定义的行为。我不确切知道编译器的作用是什么,以及为什么它调用默认构造函数 1 - 但这是你未定义的行为。
1 虽然我有一个理论:它可能会尝试初始化r
,g
,b
和a
。
答案 1 :(得分:2)
首先,C ++没有匿名结构。所以这个Vector4成员的定义
union
{
struct { T x, y, z, w; };
struct { T r, g, b, a; };
};
不符合C ++。我认为您使用具有此类语言扩展名的 MS VC ++ 。
现在让我们考虑一下会发生什么。
在模板构造函数的mem-initializer列表中
template <typename U>
Vector4(Vector4<U>& other) : x((T)other.x), y((T)other.y), z((T)other.z), w((T)other.w) { }
C样式转换,例如(T)other.x
调用类half
的构造函数
explicit half(float pattern) : data(16) { printf("half::from_float_constructor\n");
此调用的结果是创建类型为half
的临时对象
您可能不应用类half
的复制构造函数,因为它的参数声明为非const引用,而临时对象可能不会绑定到非const引用。
half(half& pattern) : data(pattern.data) { printf("half::copy_constructor\n"); }
因此构造函数会搜索其他路径来执行该任务。
它可以将临时对象转换为float
类型的对象operator float() { printf("half::to_float_operator\n"); return 3.0f; }
};
在最后一个构造函数中调用
explicit half(float pattern) : data(16) { printf("half::from_float_constructor\n"); }
因此,您可以获得以下消息序列
half::from_float_constructor
half::to_float_operator
half::from_float_constructor
我准备了一个更简单的C ++兼容示例,演示了相同的行为
#include <iostream>
struct A
{
float x = 0.0f;
};
struct B
{
explicit B( float ){ std::cout << "B::from_float_constructor" << std::endl; }
B( B & ){ std::cout << "B::from_copy_constructor" << std::endl; }
operator float () const
{
std::cout << "B::to_float_operator" << std::endl;
return 0.0f;
}
};
struct C
{
B b;
C( A a ) : b( ( B )a.x ) {}
};
int main()
{
A a;
C c( a );
return 0;
}
输出
B::from_float_constructor
B::to_float_operator
B::from_float_constructor