我只是想在这里弄清楚这段代码发生了什么,以及为什么这样做:
main.cpp
string mathFunc = "Round";
MethodInfo method = typeof(Math).GetMethod(mathFunc, new[] {typeof(double) });
Console.WriteLine(method.Invoke(null, new object [] { 1.78d }));
我的主函数中的代码不变,因为两种情况都相同:
这是我正在工作的#include <fstream>
#include <iostream>
#include <iomanip>
#include <sstream>
#include "Register.h"
int main() {
using namespace vpc;
Reg8 r8{ 0xEF };
Reg16 expected{ 478 };
Reg16 r16a = r8 + r8;
Reg16 r16b{ r8 + r8 };
std::cout << expected << r16a << r16b;
return EXIT_SUCCESS;
}
,这是我的第一次尝试:
operator+
这是程序的输出:
输出v1
template<typename Lhs, typename Rhs>
auto operator+(const Register<Lhs>& l, const Register<Rhs>& r) {
auto tmp = l.value + r.value;
if (sizeof(l.value) < sizeof(r.value))
return Register<Rhs>{ tmp };
else
return Register<Lhs>{ tmp };
}
如上所示,期望值应为Reg16(478)
Prev: 0
hex: 0x01DE
bin: 0000000111011110
Reg16(222)
Prev: 0
hex: 0x00DE
bin: 0000000011011110
Reg16(222)
Prev: 0
hex: 0x00DE
bin: 0000000011011110
(十进制)或478
(十六进制)。但是,在这种情况下,0x01DE
和operator=
构造函数无法从Register<T>
获得适当的值。
通过将operator+
更改为此,我可以解决此问题:
operator+
这给了我正确的结果:
输出v2
template<typename Lhs, typename Rhs>
auto operator+(const Register<Lhs>& l, const Register<Rhs>& r) {
return Register<decltype(l.value + r.value)>{ l.value + r.value };
}
如果您需要查看我的完整类的实现,可以在我的问题(关注)下方找到它:我正在这里寻求清晰性和对行为的更好理解。
我想知道的是为什么第一个版本没有产生正确或期望的值,以及为什么第二个尝试却没有产生正确或期望的值。两种实现之间的主要区别是什么,以及编译器内部发生了什么?我正在使用Visual Studio 2017。
注册。h
Reg16(478)
Prev: 0
hex: 0x01DE
bin: 0000000111011110
Reg16(478)
Prev: 0
hex: 0x01DE
bin: 0000000111011110
Reg16(478)
Prev: 0
hex: 0x01DE
bin: 0000000111011110
答案 0 :(得分:2)
三点。
(1)请记住,在您的第一版if constexpr
中使用if
而不是简单地使用operator+ ()
template<typename Lhs, typename Rhs>
auto operator+(const Register<Lhs>& l, const Register<Rhs>& r) {
auto tmp = l.value + r.value;
if constexpr (sizeof(l.value) < sizeof(r.value)) // if constexpr here!
return Register<Rhs>{ tmp };
else
return Register<Lhs>{ tmp };
}
否则,当auto
与sizeof(l.value)
不同时,sizeof(r.value)
推导类型将不起作用。
(2)从operator()
的第一个版本开始(之所以有效,是因为您将两个相同类型的值相加),所以出现了溢出。
更确切地说:
Lhs
和Rhs
是std::uint8_t
,因此该函数返回Register<std::uint8_t>
。tmp
成为std::uint32_t
(请参阅第3点),但将其分配给std::uint8_t
可以消除溢出(3)从我的平台,从代码
std::cout << sizeof(char) << std::endl;
std::cout << sizeof(std::declval<char>()+std::declval<char>()) << std::endl;
std::cout << sizeof(short) << std::endl;
std::cout << sizeof(std::declval<short>()+std::declval<short>()) << std::endl;
我明白了
1
4
2
4
这称为“整体促销”。
简而言之:两个char
之和成为int
;两个short
之和成为int
。
这应该说明为什么您的第二版operator+ ()
有效(但我想不是完全如此)
template<typename Lhs, typename Rhs>
auto operator+(const Register<Lhs>& l, const Register<Rhs>& r) {
return Register<decltype(l.value + r.value)>{ l.value + r.value };
}
您认为decltype(l.value + r.value)
是int
;因此decltype(R8+R8)
是R32
。
答案 1 :(得分:1)
什么是Rhs
和Lhs
r8 + r8
被称为?两者均为uint8_t
,因此在第一版
auto tmp = l.value + r.value;
if (sizeof(l.value) < sizeof(r.value))
return Register<Rhs>{ tmp };
else
return Register<Lhs>{ tmp };
临时tmp = 478
传递给Register
类型为value
的{{1}},并且您会丢失数据。
第二版
uint8_t
您正在使用return Register<decltype(l.value + r.value)>{ l.value + r.value };
来获取decltype
的类型。两种类型均为l.value + r.value
,但是在执行整数运算时,它们都被提升为uint_8
,因此int
返回decltype()
,int
的宽度足以存储478。