Sign in to follow this  
iLoveGameProgramming

Unity Singleton and template Error (C++)

Recommended Posts

Hello, First of all thank you for taking time to help.

I recently started playing around with templates and singletons. I'm trying to make something like Unity's Debug.Log but in C++. Starting with simple things like cout. Unfortunately I got stuck and with all the googling I can't seem to find how to solve this issue without not making class singleton. Maybe there is better way of doing this?

 

//Console.h

#pragma once
#include <iostream>

class Console
{
private:
	Console() {}
	~Console() {}
public:
	static Console& instance()
	{
		static Console INSTANCE;
		return INSTANCE;
	}

	template <class T>
	void Print(T arg);

};

//Console.cpp

#include "Console.h"

template <class T>
void Console::Print(T arg)
{
	std::cout << arg.c_str() << std::endl;
}

//main.cpp

#include "Console.h"
int main(int argc, char *argv[])
{
	Console::instance().Print(5);
	return 0;
}

The error is:

Error 1 error LNK2019: unresolved external symbol "public: void __thiscall Console::Print<int>(int)" (??$Print@H@Console@@QAEXH@Z) referenced in function _main E:\WORK\InLine2D\InLine2D\InLine2D\main.obj InLine2D
Error 2 error LNK1120: 1 unresolved externals E:\WORK\InLine2D\InLine2D\Debug\InLine2D.exe 1 1 InLine2D
 
Edited by Konrad Jablonski

Share this post


Link to post
Share on other sites
fastcall22    10846
Unless you explicitly list out all template instantiations, you cannot separate the template into header and source files.

See also: Why can’t I separate the definition of my templates class from its declaration and put it inside a .cpp file?


That aside, you shouldn't use globals because blah blah blah.

EDIT:
SeanMiddleditch has a valid point Edited by fastcall22

Share this post


Link to post
Share on other sites

Unless you explicitly list out all template instantiations, you cannot separate the template into header and source files.

See also: http://www.parashift.com/c++-faq/templates-defn-vs-decl.html

 

Thank you, this makes much more sense now. I swear I had it in one place at one point, but I was getting other errors and thought it was because of that. Just changed it to one file and it's all working now. It's my first time using templates by the way, trying to learn more C++.  Thank you.

Edited by Konrad Jablonski

Share this post


Link to post
Share on other sites
frob    44977


The singleton, a type that can only have one instance ever created, where attempting to create more than one is forbidden by code, that is something to avoid. Even on consoles still a terrible idea. Even for logging where some people suggest it is good, it is a terrible idea: I've worked on plenty of projects where I wanted a private logging system.


A well-known instance, sometimes implemented as pointers within a globally readable data structure, is sometimes a compromise made in coding design.

These well-known instances are NOT singletons (you can create multiple instances if needed) and they are not globals (statically allocated objects), but they are dynamically allocated objects with well-known pointer locations, and they come with strict rules about who can use them for what. These also need to have carefully reviewed, vigorously enforced policies to ensure they are not misused, treating them as short-lived constants in almost all places, with well-defined times of when they can change, such as outside of Update() loops.

Sometimes these well-known instances are managed through a single global object that is nothing more than a bunch of pointers. So you could access it through ::Systems.audio->method(), but there are some big concerns about it. If you are careful that they are mutable and immutable at the right times -- that is they are not modified by using them and that they are only modified at specific times, then it can sometimes work out.

The worst bugs are the ones where those values are modified at the wrong time or by systems unknown. Without warning the behavior of the game is suddenly different, and you cannot find who modified what, when, or why. Suddenly a state was set or a value was modified, and you don't know which of the many systems that could have modified it did so in the wrong spot. Those are nightmares, and the reason globals and mutable shared state are considered terrible design generally.

Share this post


Link to post
Share on other sites
SeanMiddleditch    17565

These well-known instances are NOT singletons


I appreciate the distinction and I agree with frob.

I'm used to using "singleton" in a sense that is probably not the same as what the Gang of Four originally described it as. smile.png

See the service locator pattern (also also here) for a better description of what I usually call a "singleton" and what (I think) frob is talking about.

Share this post


Link to post
Share on other sites
SeanMiddleditch    17565
For further example, the "singletons" I prefer look something like this:

class IResourceMgr {
public:
  virtual ~IResourceMgr() = default;

  static IResourceMgr& Instance();
  static void ResetInstance(std::unique_ptr<IResourceMgr> instance = nullptr);

  virtual Load() = 0;
  virtual Foo() = 0;
  virtual Bar() = 0;
};
Most user code accesses the above just like the regular singleton pattern prescribes (hence why I call it such), but you can still control the lifetime.

You can pass around any sort of IResourceMgr as you see fit (if you need local temporary, for example), you are still in absolute control of lifetime, you can override the implementation for mocks and testing, and you can select to use a stack-based approach (PushInstance and PopInstance, roughly) when it makes sense to do so.

Share this post


Link to post
Share on other sites
frob    44977

Just be aware, service locators and well-known instances can be a source of nasty bugs and serious design flaws.

 

The pattern introduces quite a lot of coupling. The coupling makes it more difficult to reuse code, where passing a parameter would have allowed reuse. The coupling has a high risk of violating several SOLID principles, it generally breaks Open/Closed, and has a high risk of breaking interface segregation and dependency inversion, but smarter developers will follow them by policy.

 

The key feature that absolutely must be followed if you want to preserve your sanity is that their behavior and use must be immutable. Any of the services being referenced must not be liable to change. They absolutely cannot change while they are in use. Functionality they control should be gated (both by policy and code rules) to prevent inappropriate changes.

 

It is generally best to pass parameters directly to methods rather than rely on these tools. There are usually better design decisions away from the patterns but those better solutions require more parameters, more thought, more insight, and more time to implement.

 

 

 

Again, the service locator / well-known instance pattern is NOT A GOOD DESIGN generally.  It is an unfortunate compromise taken when design is bad, when other programmers incorrectly coupled features, and when you cannot take the time to break the couplings properly.  It should not be the first tool you reach for. It is an unfortunate crutch, a compromise made due to tight deadlines and the sad reality that too much code, both design and implementation, seriously stinks. 

 

It is not a thing to be proud of.  It is a thing that you are best removing from the code as quickly as possible.  It is a code smell, a technical debt, not a point of glory.

Share this post


Link to post
Share on other sites
SeanMiddleditch    17565

It is not a thing to be proud of.  It is a thing that you are best removing from the code as quickly as possible.  It is a code smell, a technical debt, not a point of glory.


And here's where I disagree. That kind of purity sounds nice on paper but is academic and just doesn't work in practice. Down that path lies passing 60 parameters to constructors and grotesque contortions just to avoid using a global here and there. All of your code because harder to read, harder to understand, and harder to maintain.

Software inherently relies on layered services. Your OS syscalls are, for all intents and purposes, services/singletons. Your hardware is a service. When you build layered software you add more of your own. There's a point at which software design and implementation simply gets more manageable when you assume layer A sits on top of layer B and don't force a decoupling where there _is_ an intrinsic and unavoidable coupling; good use of globals/singletons/services can accomplish that with no _actual_ problems (despite all the hypothetical ones you might come up with).

Dogmatic application of pithy principles gets you nowhere. At least, nowhere you want to be. I've been there. smile.png

Share this post


Link to post
Share on other sites
Bacterius    13165

I have to agree with Sean here, I am seriously tired of dealing with the cognitive overhead of dependency injection frameworks that have me forced to pass the same damn object around everywhere because it's sufficiently basic and low-level that everything needs it, and at the end of the day it's still a global because everything everywhere has a reference to the exact same object. Things are just as bad as with a global, except now I have a dependency injection framework with it and my code's simple logic is obscured by a weird meta-language to describe its relationship with other simple dependencies (parameter-passing in constructors/factories, annotations, XML dependency trees; pick your poison). I do not see a problem with having genuine services as long as their interface is sane, nor am I against explicitly codifying abstract dependencies when it makes sense and adds value. I have a brain and my colleagues do as well, and at work I find that most of it is being used working with against "modern" design patterns and contorting straightforward code to fit someone else's idea of "decoupled code" instead of actually implementing business logic, and probably producing far more bugs as a result. As everything else in life, design principles become bad and dangerous when taken in excess. If in doubt, stop and think.

 

Anyway frob I found it interesting that you used the word "generally" followed by an unconditional statement. What in your opinion would be an uncommon use case where a singleton or service locator would be a sensible design choice?

Share this post


Link to post
Share on other sites
Ryan_001    3476

I have to agree with Sean here, I am seriously tired of dealing with the cognitive overhead of dependency injection frameworks that have me forced to pass the same damn object around everywhere because it's sufficiently basic and low-level that everything needs it, and at the end of the day it's still a global because everything everywhere has a reference to the exact same object. Things are just as bad as with a global, except now I have a dependency injection framework with it and my code's simple logic is obscured by a weird meta-language to describe its relationship with other simple dependencies (parameter-passing in constructors/factories, annotations, XML dependency trees; pick your poison). I do not see a problem with having genuine services as long as their interface is sane, nor am I against explicitly codifying abstract dependencies when it makes sense and adds value. I have a brain and my colleagues do as well, and at work I find that most of it is being used working with against "modern" design patterns and contorting straightforward code to fit someone else's idea of "decoupled code" instead of actually implementing business logic, and probably producing far more bugs as a result. As everything else in life, design principles become bad and dangerous when taken in excess. If in doubt, stop and think.

 

Anyway frob I found it interesting that you used the word "generally" followed by an unconditional statement. What in your opinion would be an uncommon use case where a singleton or service locator would be a sensible design choice?

 

Completely agree.

Share this post


Link to post
Share on other sites
Bregma    9214


Error 2 error LNK1120: 1 unresolved externals E:\WORK\InLine2D\InLine2D\Debug\InLine2D.exe 1 1 InLine2D

Anyway, back to the OP's question.

 

Whenever you're trying to do something in C++, it's always a good idea to look to see how the standard C++ already does it, because there have been a lot of expert input into the design and implementation of the standard C++ library.

 

In the standard C++ library, there is a global console logging object with a set of overloaded and templatized functions for inserting into it.  In fact, you're trying to create a similar Java-style singleton class to wrap the standard object that already does exactly what you need, except not in the style a Java develop mey be accustomed to, with static member functions returning object instances that are used to invoke instanced functions with overloaded procedures for combining formatting and streaming functions.

 

In the C++ standard library you will find a set of global logging stream objects that are designed to be instantiated on first use:  std::cout, std::cerr, and std::clog.  They have an accompanying suite of overloaded and templatized functions (operator<<()) that perform manipulation and insertion into those logging streams.  They have already solved your problems, consider using them instead of wrapping them in your own problematic code, or at least examine their design and emulate it yourself.

 

The C++ standard library logging objects are designed to be extended not only by overloading operator<<() for your own types but by replacing their streambuf to give you control over things like final destination or setting categories and severities.  Notice the post linked to there was addressing pretty much exactly the same topic as this one, and is dated 2006.  The aswer is still completely valid over a decade later.

Share this post


Link to post
Share on other sites

Create an account or sign in to comment

You need to be a member in order to leave a comment

Create an account

Sign up for a new account in our community. It's easy!

Register a new account

Sign in

Already have an account? Sign in here.

Sign In Now

Sign in to follow this  

  • Partner Spotlight

  • Similar Content

    • By Levgre
      I have a design doc I can share, either contact me here, at levgree@yahoo.com, or on Discord (tag is levgre#1415). I am only going over some of mechanics in this post, with more focus on combat than campaign, as combat is the core of the game.  designers could possibly be welcome, at the least I don't ever mind getting additional ideas/feedback.
      Like said in the title, the game is inspired by Darkest Dungeon, but aspiring for deeper and more varied combat/campaign mechanics.
      Theme: the player controls a party of raiders that go on missions, getting loot, building up reputation and experience, etc.  These missions would often be populated areas like towns and forts, but also could be caves, forests, and other settings.  
      The player will control a party of 6 characters.  Changing group formation and individual character positions will be an essential part of strategy for all party compositions.   However, most characters will still be in melee combat, as often the party will be fighting off enemies from both sides (just less often from the rear).
      Characters, both friendly and enemy, will be able to die or be severely injured in one hit, and no magical healing available.  However they will be able to dodge or deflect most attacks until they run out of "stamina", at which point they become sluggish and easier to kill.  So gameplay wise, stamina behaves sort of like the regenerating shield in halo.  However if the player makes a tactical error or puts a character in a situation where they are outmatched, characters could still be wounded even at full stamina.  So individual battles are not the only threat, but also tiring  from waves of enemies.
       The player's group can rest when needed, but that will allow the enemies to ready their defenses or get reinforcements.  So speed and smart stamina management is encouraged.  Although, there will be some level of variety in approach, the player could have a more heavily armored team that slogs through tougher fights, or a lightly armored quick characters for a fast team that relies more on the element of surprise. 
      Weapon and armor choices for each character will be significant strategic decisions, based on battle formation and also the strengths and weaknesses of the party comp/individual characters.
      The exact setting is not yet decided, it could be realistic medieval, high fantasy medieval with demihumans and magical creatures and some level of magic, steampunk, etc..  The "raiders" could be seafaring viking types, fighting in a religious conflict like crusaders, or some of both.
      Thanks for reading, and lmk if you are interested or have any questions.
    • By Spronx
      Hi guys,
      I'm Andy from StriX Interactive and we are
      LOOKING FOR A LEVEL DESIGNER
      to join us on this incredible adventure of developing Blood Oath. Open world fantasy 3rd person RPG in the style of The Witcher.
      We plan to launch a Kickstarter campaign by the end of the year. So it's not a paid job yet.
      We need someone capable of making terrain according to the world map that we have and over all level design. We have a great team and want YOU to be a part of it.
      Contact us on our facebook page https://www.facebook.com/StriXInteractive/

    • By Java Nigga
      Hi there!
      We are JN Studios, we are looking for people to work with us in our project.
      About US:
      JN Studios is a 2 people amateur studio. we have like 1 year making games, but this is our first professional project to show it to the public. We are a programmer guy(Me) and a 3d modeller.
      About the game:
      Strategist Sniper is a RPG/FPS game, yes RPG and fps :v you awake in the middle of the unknown and a small voice tells you that you have to go through the world killing other snipers to get out of there. the mechanics of the game are based on the basic controls of games like League of Legends and in FPS games like Counter Strike.
      What we are looking for?
      actually we are looking for another c# programmer, a musician and an artist(for game illustrations for the marketing of the game).
      Profits Share:
      when the game is in a stable alpha phase we will create a campaign in Idiegogo to obtain money to finance the game. each of the project participants will receive a percentage depending on the work done.
      How to apply?
      just send us a email with a portfolio and in what you can help our team -       trabajojava1@gmail.com


      Devblog1.mp4
    • By cursetalegame
      Hello! I am building the main scene in Unity for a 3D cards game. My goal is creating "card slots" to place the different cards from a deck and use it as "buttons". The image below represents somehow what I want to develop. I have been reading and I think that I have to generate a canvas and place in my scene the slots where I want to place the cards, but I am not sure about it. Also, to use the cards, I don't know if setting buttons is the best option (maybe I should use images instead).
      All recommendations and tips are welcome

    • By cursetalegame
      Hi! We are looking for a unity 3D developer to join our small "beginners" team. We are 3 artists (illustration, concept and 3D modeling), 2 designers and 1 programmer (me). We are developing an online video game that we have already designed. Our goal is to create a small studio and build up this game to take it to video game events around Europe and try to find publishers. Also we want to learn step by step how to develop games, so, is better if you don't have a huge experience in developing
      For more information, or any question, you can send us an email to cursetalegame@gmail.com 
      Cheers
  • Popular Now