• Advertisement
Sign in to follow this  

Unity Singleton and template Error (C++)

This topic is 875 days old which is more than the 365 day threshold we allow for new replies. Please post a new topic.

If you intended to correct an error in the post then please contact us.

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
Advertisement
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


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

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
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

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

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

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

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


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
Sign in to follow this  

  • Advertisement
  • Advertisement
  • Popular Tags

  • Advertisement
  • Popular Now

  • Similar Content

    • By GytisDev
      Hello,
      without going into any details I am looking for any articles or blogs or advice about city building and RTS games in general. I tried to search for these on my own, but would like to see your input also. I want to make a very simple version of a game like Banished or Kingdoms and Castles,  where I would be able to place like two types of buildings, make farms and cut trees for resources while controlling a single worker. I have some problem understanding how these games works in the back-end: how various data can be stored about the map and objects, how grids works, implementing work system (like a little cube (human) walks to a tree and cuts it) and so on. I am also pretty confident in my programming capabilities for such a game. Sorry if I make any mistakes, English is not my native language.
      Thank you in advance.
    • By Ovicior
      Hey,
      So I'm currently working on a rogue-like top-down game that features melee combat. Getting basic weapon stats like power, weight, and range is not a problem. I am, however, having a problem with coming up with a flexible and dynamic system to allow me to quickly create unique effects for the weapons. I want to essentially create a sort of API that is called when appropriate and gives whatever information is necessary (For example, I could opt to use methods called OnPlayerHit() or IfPlayerBleeding() to implement behavior for each weapon). The issue is, I've never actually made a system as flexible as this.
      My current idea is to make a base abstract weapon class, and then have calls to all the methods when appropriate in there (OnPlayerHit() would be called whenever the player's health is subtracted from, for example). This would involve creating a sub-class for every weapon type and overriding each method to make sure the behavior works appropriately. This does not feel very efficient or clean at all. I was thinking of using interfaces to allow for the implementation of whatever "event" is needed (such as having an interface for OnPlayerAttack(), which would force the creation of a method that is called whenever the player attacks something).
       
      Here's a couple unique weapon ideas I have:
      Explosion sword: Create explosion in attack direction.
      Cold sword: Chance to freeze enemies when they are hit.
      Electric sword: On attack, electricity chains damage to nearby enemies.
       
      I'm basically trying to create a sort of API that'll allow me to easily inherit from a base weapon class and add additional behaviors somehow. One thing to know is that I'm on Unity, and swapping the weapon object's weapon component whenever the weapon changes is not at all a good idea. I need some way to contain all this varying data in one Unity component that can contain a Weapon field to hold all this data. Any ideas?
       
      I'm currently considering having a WeaponController class that can contain a Weapon class, which calls all the methods I use to create unique effects in the weapon (Such as OnPlayerAttack()) when appropriate.
    • By Vu Chi Thien
      Hi fellow game devs,
      First, I would like to apologize for the wall of text.
      As you may notice I have been digging in vehicle simulation for some times now through my clutch question posts. And thanks to the generous help of you guys, especially @CombatWombat I have finished my clutch model (Really CombatWombat you deserve much more than a post upvote, I would buy you a drink if I could ha ha). 
      Now the final piece in my vehicle physic model is the differential. For now I have an open-differential model working quite well by just outputting torque 50-50 to left and right wheel. Now I would like to implement a Limited Slip Differential. I have very limited knowledge about LSD, and what I know about LSD is through readings on racer.nl documentation, watching Youtube videos, and playing around with games like Assetto Corsa and Project Cars. So this is what I understand so far:
      - The LSD acts like an open-diff when there is no torque from engine applied to the input shaft of the diff. However, in clutch-type LSD there is still an amount of binding between the left and right wheel due to preload spring.
      - When there is torque to the input shaft (on power and off power in 2 ways LSD), in ramp LSD, the ramp will push the clutch patch together, creating binding force. The amount of binding force depends on the amount of clutch patch and ramp angle, so the diff will not completely locked up and there is still difference in wheel speed between left and right wheel, but when the locking force is enough the diff will lock.
      - There also something I'm not sure is the amount of torque ratio based on road resistance torque (rolling resistance I guess)., but since I cannot extract rolling resistance from the tire model I'm using (Unity wheelCollider), I think I would not use this approach. Instead I'm going to use the speed difference in left and right wheel, similar to torsen diff. Below is my rough model with the clutch type LSD:
      speedDiff = leftWheelSpeed - rightWheelSpeed; //torque to differential input shaft. //first treat the diff as an open diff with equal torque to both wheels inputTorque = gearBoxTorque * 0.5f; //then modify torque to each wheel based on wheel speed difference //the difference in torque depends on speed difference, throttleInput (on/off power) //amount of locking force wanted at different amount of speed difference, //and preload force //torque to left wheel leftWheelTorque = inputTorque - (speedDiff * preLoadForce + lockingForce * throttleInput); //torque to right wheel rightWheelTorque = inputTorque + (speedDiff * preLoadForce + lockingForce * throttleInput); I'm putting throttle input in because from what I've read the amount of locking also depends on the amount of throttle input (harder throttle -> higher  torque input -> stronger locking). The model is nowhere near good, so please jump in and correct me.
      Also I have a few questions:
      - In torsen/geared LSD, is it correct that the diff actually never lock but only split torque based on bias ratio, which also based on speed difference between wheels? And does the bias only happen when the speed difference reaches the ratio (say 2:1 or 3:1) and below that it will act like an open diff, which basically like an open diff with an if statement to switch state?
      - Is it correct that the amount of locking force in clutch LSD depends on amount of input torque? If so, what is the threshold of the input torque to "activate" the diff (start splitting torque)? How can I get the amount of torque bias ratio (in wheelTorque = inputTorque * biasRatio) based on the speed difference or rolling resistance at wheel?
      - Is the speed at the input shaft of the diff always equals to the average speed of 2 wheels ie (left + right) / 2?
      Please help me out with this. I haven't found any topic about this yet on gamedev, and this is my final piece of the puzzle. Thank you guys very very much.
    • By Estra
      Memory Trees is a PC game and Life+Farming simulation game. Harvest Moon and Rune Factory , the game will be quite big. I believe that this will take a long time to finish
      Looking for
      Programmer
      1 experience using Unity/C++
      2 have a portfolio of Programmer
      3 like RPG game ( Rune rune factory / zelda series / FF series )
      4 Have responsibility + Time Management
      and friendly easy working with others Programmer willing to use Skype for communication with team please E-mail me if you're interested
      Split %: Revenue share. We can discuss. Fully Funded servers and contents
      and friendly easy working with others willing to use Skype for communication with team please E-mail me if you're interested
      we can talk more detail in Estherfanworld@gmail.com Don't comment here
      Thank you so much for reading
      More about our game
      Memory Trees : forget me not

      Thank you so much for reading
      Ps.Please make sure that you have unity skill and Have responsibility + Time Management,
      because If not it will waste time not one but both of us
       

  • Advertisement