Compiler error with specialized template class

I have this template class:

template <typename ResultType>
	class TaskResult: public BArchivable {
	public:
		
		TaskResult(const BMessage &archive) 
		{
			// archive.PrintToStream();
			void *data = nullptr;
			ssize_t size = 0;
			type_code type;
			
			if (archive.GetInfo(fResultFieldName, &type) == B_OK) {
				status_t error = archive.FindData(fResultFieldName, type, 
													(const void**)&data, &size);
				if (error != B_OK)
					throw runtime_error("Can't unarchive TaskResult instance");
				else
					fResult = *(ResultType*)(data);
			} else {
				throw runtime_error("Can't unarchive TaskResult instance");
			}
			
			if (archive.FindInt32(fResultTaskIdName, &fId) != B_OK) {
					throw runtime_error("Can't unarchive TaskResult instance");
			}
		}
		
		~TaskResult() {}

		ResultType	GetResult() 
		{ 		
			auto ptr = TaskExceptionMap[fId];
			if (ptr)
				rethrow_exception(ptr);
			else
				return fResult; 
		}
		
		virtual status_t Archive(BMessage *archive, bool deep)
		{
			status_t result;
			result = BArchivable::Archive(archive, deep);
			
			type_code type = BMessageType<ResultType>::Get();
			result = archive->AddData(fResultFieldName, type, &fResult, sizeof(fResult));
			result = archive->AddInt32(fResultTaskIdName, fId);
			
			result = archive->AddString("class", "TaskResult");
		   
			return result;
		}
		
		static BArchivable* Instantiate(BMessage* archive)
		{
			if (validate_instantiation(archive, "TaskResult"))
				return new TaskResult<ResultType>(archive);
			else
				return nullptr;
		}

	private:
		friend class	Task<ResultType>;
		const char*		fResultFieldName = "TaskResult::Result";
		const char*		fResultTaskIdName = "TaskResult::ID";
		ResultType		fResult;
		thread_id		fId;
		
						TaskResult() {}
		
	};
	
	template <>
	class TaskResult<void>: public BArchivable {
	public:
		
		TaskResult(const BMessage &archive) 
			: fResult(true)
		{
			// archive.PrintToStream();
					
			if (archive.FindInt32(fResultTaskIdName, &fId) != B_OK) {
					throw runtime_error("Can't unarchive TaskResult instance");
			}
		}
		
		~TaskResult() {}

		void	GetResult() 
		{ 		
			auto ptr = TaskExceptionMap[fId];
			if (ptr)
				rethrow_exception(ptr);
		}
		
		virtual status_t Archive(BMessage *archive, bool deep) const
		{
			status_t result;
			result = BArchivable::Archive(archive, deep);
			
			result = archive->AddInt32(fResultTaskIdName, fId);
			
			result = archive->AddString("class", "TaskResult");
		   
			return result;
		}
		
		static BArchivable* Instantiate(BMessage* archive)
		{
			if (validate_instantiation(archive, "TaskResult"))
				return new TaskResult<void>(archive);
			else
				return nullptr;
		}

	private:
		friend class	Task<void>;
		const char*		fResultFieldName = "TaskResult::Result";
		const char*		fResultTaskIdName = "TaskResult::ID";
		bool			fResult;
		thread_id		fId;
		
						TaskResult() {}
		
	};

It fails to compile with this error:

In file included from src/helpers/Task.cpp:7:
src/helpers/Task.h: In static member function 'static BArchivable* Genio::Task::TaskResult<void>::Instantiate(BMessage*)':
src/helpers/Task.h:252:68: error: 'BMessage::BMessage(BMessage*)' is private within this context
  252 |                                 return new TaskResult<void>(archive);
      |                                                                    ^
In file included from /boot/system/develop/headers/os/support/Archivable.h:10,
                 from /boot/system/develop/headers/os/app/Handler.h:12,
                 from /boot/system/develop/headers/os/app/Looper.h:13,
                 from /boot/system/develop/headers/os/interface/Window.h:9,
                 from /boot/system/develop/headers/os/interface/Alert.h:11,
                 from src/helpers/Utils.h:13,
                 from src/helpers/Task.h:13:
/boot/system/develop/headers/os/app/Message.h:560:65: note: declared private here
  560 |                                                                 BMessage(BMessage* message);
      |                                                                 ^~~~~~~~

I can’t figure out why return new TaskResult<void>(archive) yields the error above.
Does anybody know why?

NOTE:
Just a bit of context here, TaskResult<> is part of a library I’m writing as part of the Genio framework.
It is a wrapper for the result of an execution unit invoked by the class:

template <typename ResultType>
	class Task {
	public:
		using native_handle_type = thread_id;

		template<typename Name, typename Messenger, typename Function, typename... Args>
		Task(Name name, Messenger messenger, Function&& function, Args&&... args)
		{}
...
}

It works like std::thread and is insipred by the thread functions and classes in libwalter but it uses modern C++ features like template packs (aka template variadic args), TAD, SFINAE, etc.
It accepts any callable with perferct argument forwarding and is declared like this:

Genio::Task::Task<status_t> task("test", new BMessenger(this), 
								&Genio::Git::GitRepository::Clone, 
								fURL->Text(), 
								fPathBox->Path());
task.Run();

at the end of the execution it sends a BMessage back to the caller by archiving a TaskResult instance.

case TASK_RESULT_MESSAGE:
{
	try {
		// auto result = TaskResult<status_t>(*msg).GetResult();
		// OKAlert("", BString("MessageReceived() Result: ") << result, B_INFO_ALERT);
		TaskResult<void>(*msg).GetResult();
		OKAlert("", BString("MessageReceived() Result:  terminated"), B_INFO_ALERT);
	} catch(std::exception &ex) {
		OKAlert("", BString("MessageReceived() Exception: ") << ex.what(), B_INFO_ALERT);
	}	
}

TaskResult also wraps any uncatched exception by transporting it to the caller via exception_ptr, current_exception() and rethrow_exception().

For the records, I have abandoned the template specialization route in favor of a true polimorfic approach using std::any. Still, I’m wondering why this old version does not compile.

As the compiler points out, the problematic line is the following block:

		static BArchivable* Instantiate(BMessage* archive)
		{
			if (validate_instantiation(archive, "TaskResult"))
				return new TaskResult<void>(archive);
			else
				return nullptr;
		}

The archive local variable is of type BMessage *.

This calls the following constructor:

		TaskResult(const BMessage &archive) 

As you can see, there is a mismatch of parameters: you are passing a pointer, but the constructor expects a reference or an object that can be referenced.

The compiler then determines that there is a way to do this conversion, which is to create a new temporary object using the BMessage::BMessage(BMessage *) constructor provided by the BMessage class. Unfortunately that has been made private, which the error shows, meaning there is no legal way to go from BMessage * to const BMessage&.

You should be able to do the following:

return new TaskResult<void>(*archive);

The compiler will then be able to create a reference to the object pointed to by the archive parameter.

Shame on me! :expressionless: Thanks a lot @nielx

The question now is why the error appears only in the template specialisation and not in the generic template. If I don’t include the specialisation all compiles without a glitch which was misleading to me.

Have you actually instantiated the template? I think you have not, and therefore you have not yet seen the error. With specialization, you actually instantiate it, and the compiler evaluates the actual code.

I have and it works flawlessly for non-void result types.

That would surprise me, but it is worth investigating. Is the Instantiate() method for that class actually called from anywhere else? My hypothesis is that the compiler is not actually generating the instantiated method unless it is necessary.

I don’t remember but it’s possible.
I’ll do some tests and report back