花式黑客在本地打破了思考,但没有在在线编译器中

问题描述

一些聪明的人: 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 {}; }