问题描述
一些聪明的人: get the number of fields in a class 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"
然后出现段错误...
我不了解所发生的事情,模板代码不应破坏我所看到的东西,但是即使我注释掉了对代码中其他函数的所有调用,它还是有某种意义。我什至不知道从哪里开始调试。
解决方法
问题在于原始代码必须(出于逃避我的原因)根据其签名返回一个值,但永远不会这样做。
解决方案是使它实际上返回某些内容以防止段错误:
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 {}; }