Coding Memo

[에러?] the template instantiation context ~ 본문

Language/C++

[에러?] the template instantiation context ~

minttea25 2024. 4. 24. 14:13

일단은 해당 내용은 에러나 경고로 나타나지 않고, 단순히 output에서 나타난 일종의 메시지 이다.

the template instantiation context (the oldest one first) is
1> ...Session.cpp(49,23):
1> see reference to function template instantiation 'std::shared_ptr<_Ty> NetCore::make_shared<NetCore::SendBufferSegment,std::shared_ptr<NetCore::SendBuffer>,NetCore::_ubyte*&,const size_t&>(std::shared_ptr<NetCore::SendBuffer> &&,NetCore::_ubyte *&,const size_t &)' being compiled
1>        with
1>        [
1>            _Ty=NetCore::SendBufferSegment
1>        ]
1> ...Memory.h(54,3):
1> see reference to function template instantiation 'Type *NetCore::xxnew<NetCore::SendBufferSegment,_Ty,NetCore::_ubyte*&,const size_t&>(_Ty &&,NetCore::_ubyte *&,const size_t &)' being compiled
1>        with
1>        [
1>            Type=NetCore::SendBufferSegment,
1>            _Ty=std::shared_ptr<NetCore::SendBuffer>
1>        ]

 

 

해당 관련 코드이다.

template<typename Type, typename... Args>
[[nodiscard]] Type* xxnew(Args&&... args)
{
	...
}

template<typename Type, typename... Args>
std::shared_ptr<Type> make_shared(Args&&... args)
{
	return std::shared_ptr<Type>
	{
		xxnew<Type>(std::forward<Args>(args)...), xxdelete<Type>
	};
}

// xxdelete는 동적할당 해제 함수에 해당
// SendBufferSegment 클래스 생성자
SendBufferSegment(std::shared_ptr<SendBuffer> buffer, unsigned char* bufferPos, unsigned int size)
	: _size(size), _buffer(buffer), _bufferPos(bufferPos)
{
}

// Session에서의 코드
auto seg = NetCore::make_shared<SendBufferSegment>(TLS_SendBuffer->shared_from_this(), pos, size);

// TLS_SendBuffer는 std::shared_ptr<SendBuffer> 타입으로 thread_local
// make_shared는 std::make_shared와 동일한 기능 (사용자 정의 shared_ptr 생성)

// using _ubyte = unsigned char
// using uint32 = unsigned int

 

물론 위 내용이 나타났음에도, 프로그램은 정상적으로 컴파일되었고, 실행도 문제 없었다. 그러나 잠재적인 문제가 되거나, 내가 의도한 코드와 다르게 될 수도 있기 때문에 해결해보기로 했다.

 

SendBufferSegment에 대한 shared_ptr를 NetCore::make_shared()로 생성 시에 문제가 생기는 것으로 보인다.

하지만, 겉보기에는 문제도 없고, 컴파일러 경고나, 에러가 나타나지 않았고, 컴파일 및 실행에 전혀 지장이 없었다.

단순히, '컴파일 시에 ~~하게 했으니 확인바람~' 정도일려나?

 


몇 가지 이유를 생각해보았다.

 

1. SendBuffer의 shared_from_this() 문제

2. xxnew에서의 문제

3. SendBufferSegment의 생성자 문제

 

첫 번째 이유를 확인하기 위해 thread_local에 있는 TLS_SendBuffer 변수도 확인했고, shared_from_this를 호출하는 위치도 바꾸어 보았지만, 별 문제가 없었다.

 

두 번째는 다른 NetCore:make_shared()라 던가, NetCore::xxnew()가 제대로 작동하는 것으로 보아 문제가 없어보였고, xxnew 호출시에도 Args에 대한 타입도 제대로 전달되고 있었다.

 

마지막으로, SendBufferSegment 생성자의 정의와 이를 호출하는 코드를 좀 더 까다롭게 확인해보았다. 일단, 정답이 여기였다.

메시지 내용을 다시 되짚어보면,

 

see reference to function template instantiation 'std::shared_ptr<_Ty> NetCore::make_shared<NetCore::SendBufferSegment,std::shared_ptr<NetCore::SendBuffer>,NetCore::_ubyte*&,const size_t&>(std::shared_ptr<NetCore::SendBuffer> &&,NetCore::_ubyte *&,const size_t &)' being compiled

 

see reference to function template instantiation 'Type *NetCore::xxnew<NetCore::SendBufferSegment,_Ty,NetCore::_ubyte*&,const size_t&>(_Ty &&,NetCore::_ubyte *&,const size_t &)' being compiled

 

원래 코드에서는 Args의 3번째 타입으로 unsigned int(uint32)가 들어가서 해당 타입으로 템플릿 인스턴스화되어야 하는데, size_t라는 타입으로 인식되고 있는 것을 알 수 있었다. 

 

실제 코드에서도 size라는 변수가 strlen()의 반환값인 size_t였다.

const auto size = strlen(buffer); // size는 size_t 타입(unsigned long long)

...

auto seg = NetCore::make_shared<SendBufferSegment>(TLS_SendBuffer->shared_from_this(), pos, size);

 

따라서 컴파일러는 이렇게 말하고 있다

 

SendBufferSegment의 shared_ptr를 만들때 호출되는 생성자의 템플릿의 원본은 Type=SendBufferSegment, Args=[std::shared_ptr<SendBuffer>, unsigned char*, unsigned int]인데, 너의 코드를 컴파일하다 보니까 Args에서 3번째 인수 타입이 unsigned int가 아니라 size_t인거 같다. 그래서 unsigned int로 하지 않고 size_t로 인스턴스를 생성했다. 다음 두 템플릿 함수로 컴파일 되었다:

NetCore::make_shared에서 Args의 3번째 타입을 size_t로,

NetCore::xxnew에서 Args의 3번째 타입을 size_t로.

(즉, 원래 버전(old version)의 인스턴스와 내가 컴파일한 인스턴스가 다르다.)

 

내 코드에서는 unsigned int와 size_t의 데이터 차이가 없기 때문에 딱히 문제가 없긴하지만, 좀 더 확실하게 하는 것이 좋다는 생각이 들었다. C++은 까다로운 언어다!


const uint32 size = static_cast<uint32>(strlen(buffer));

 

위와 같이 캐스팅하여 size의 값을 기존 타입인 uint32로 확실하게 지정하여, 해당 메시지가 더 이상 나타나지 않게 할 수 있었다.

 

아니면 explicit를 활용하여 암시적 형변환에 제한을 두어서 확실하게 코드를 짜는 방법도 있겠다!!