花哨的黑客在本地而不是在在线编译器中打破反射
Fancy hack to get reflection breaking locally but not in online compiler
某位聪明人:
https://www.youtube.com/watch?v=abdeAew3gmQ
想出了如何使用模板元编程来进行一些基本的反射。
好吧,我正在尝试将其与我的代码集成,但它导致了问题。
在在线编译器中这有效:
#include <iostream>
#include <tuple>
#include <iostream>
#include <array>
#include <utility>
using namespace std;
template <std::size_t I>
struct ubiq_constructor
{
template <class Type>
constexpr operator Type&() const noexcept;
};
template <class T, std::size_t I0, std::size_t... I>
constexpr auto detect_fields_count(std::size_t& out, std::index_sequence<I0, I...>)
-> decltype( T{ ubiq_constructor<I0>{}, ubiq_constructor<I>{}... } )
{ out = sizeof...(I) + 1; }
template <class T, std::size_t... I>
constexpr void detect_fields_count(std::size_t& out, std::index_sequence<I...>) {
detect_fields_count<T>(out, std::make_index_sequence<sizeof...(I) - 1>{});
}
struct POD {
int f1;
float f2;
char h;
char w;
};
int main()
{
std::size_t size;
detect_fields_count<POD>(size, std::make_index_sequence<sizeof(POD)>());
cout << "size:" << size << endl;
return 0;
}
输出:size:4
然而,当我把它放在一个更大的项目本地项目中时,它是用 gcc 编译的,我得到的似乎是 UB。我的程序提前终止,有时会遇到段错误,但有时甚至不会发生这种情况,我的代码只是停止,甚至 gdb 都不知道为什么。
我通过的所有测试,代码编译时只有一个警告(这是模板的一部分),如果我注释掉对它的任何调用,代码将正常运行,即
int example()
{
cout << "AAAAAAAAAAAAAAAA: " << endl;
std::size_t size = 0;
detect_fields_count<POD>(size, std::make_index_sequence<sizeof(POD)>());
cout << "size: " << size << endl;
return 0;
}
在那个例子中,如果我注释掉 detect_fields_count
我的代码有效,否则,我可能会得到一个段错误,我可能会双重打印 "AAAAAAAAA"
然后得到一个段错误...
我不明白发生了什么,据我所知,模板化代码不应该破坏某些东西,但不知何故,即使我在我的代码中注释掉对其他函数的所有调用也是如此。我什至不知道从哪里开始调试这个。
问题是原始代码必须(出于我无法理解的原因)return 一个根据其签名的值,但它从来没有。
解决方案实际上是return防止段错误的东西:
template <class T, std::size_t I0, std::size_t... I>
constexpr auto detect_fields_count(std::size_t& out, std::index_sequence<I0, I...>)
-> decltype( T{ ubiq_constructor<I0>{}, ubiq_constructor<I>{}... } )
{ out = sizeof...(I) + 1; return {}; }
某位聪明人:
想出了如何使用模板元编程来进行一些基本的反射。
好吧,我正在尝试将其与我的代码集成,但它导致了问题。
在在线编译器中这有效:
#include <iostream>
#include <tuple>
#include <iostream>
#include <array>
#include <utility>
using namespace std;
template <std::size_t I>
struct ubiq_constructor
{
template <class Type>
constexpr operator Type&() const noexcept;
};
template <class T, std::size_t I0, std::size_t... I>
constexpr auto detect_fields_count(std::size_t& out, std::index_sequence<I0, I...>)
-> decltype( T{ ubiq_constructor<I0>{}, ubiq_constructor<I>{}... } )
{ out = sizeof...(I) + 1; }
template <class T, std::size_t... I>
constexpr void detect_fields_count(std::size_t& out, std::index_sequence<I...>) {
detect_fields_count<T>(out, std::make_index_sequence<sizeof...(I) - 1>{});
}
struct POD {
int f1;
float f2;
char h;
char w;
};
int main()
{
std::size_t size;
detect_fields_count<POD>(size, std::make_index_sequence<sizeof(POD)>());
cout << "size:" << size << endl;
return 0;
}
输出:size:4
然而,当我把它放在一个更大的项目本地项目中时,它是用 gcc 编译的,我得到的似乎是 UB。我的程序提前终止,有时会遇到段错误,但有时甚至不会发生这种情况,我的代码只是停止,甚至 gdb 都不知道为什么。
我通过的所有测试,代码编译时只有一个警告(这是模板的一部分),如果我注释掉对它的任何调用,代码将正常运行,即
int example()
{
cout << "AAAAAAAAAAAAAAAA: " << endl;
std::size_t size = 0;
detect_fields_count<POD>(size, std::make_index_sequence<sizeof(POD)>());
cout << "size: " << size << endl;
return 0;
}
在那个例子中,如果我注释掉 detect_fields_count
我的代码有效,否则,我可能会得到一个段错误,我可能会双重打印 "AAAAAAAAA"
然后得到一个段错误...
我不明白发生了什么,据我所知,模板化代码不应该破坏某些东西,但不知何故,即使我在我的代码中注释掉对其他函数的所有调用也是如此。我什至不知道从哪里开始调试这个。
问题是原始代码必须(出于我无法理解的原因)return 一个根据其签名的值,但它从来没有。
解决方案实际上是return防止段错误的东西:
template <class T, std::size_t I0, std::size_t... I>
constexpr auto detect_fields_count(std::size_t& out, std::index_sequence<I0, I...>)
-> decltype( T{ ubiq_constructor<I0>{}, ubiq_constructor<I>{}... } )
{ out = sizeof...(I) + 1; return {}; }