SFML community forums

Help => General => Topic started by: jokoon on August 17, 2014, 08:31:36 pm

Title: Specializing the << operator for SFML types
Post by: jokoon on August 17, 2014, 08:31:36 pm
I managed to specialize the operator<< for Vector2<> and Color on MSVC 2012, but my code doesn't work on xcode 5.

namespace sf {
    ostream & operator<< (ostream & os, const sf::Color &right)
    {
        os << right.r << " " << right.g << " " << right.b; return os;
    }
    template<typename Type>
    inline ostream& operator<<(ostream& os,const sf::Vector2<Type>& rhs)
    {
        os.precision(2);
        return os<<'['<<rhs.x<<", "<<rhs.y<<']';
    }
}
 

My code is inside a header and inside include guards. I tried with and without inline, with and without namespace sf{}.

I'm getting duplicate symbol error for each .o file that I'm linking.

I'm guessing I'm not the only one specializing this operator. clang and MSVC sure seem to not compile templates the same way. What is working for you ?
Title: Re: Specializing the << operator for SFML types
Post by: Nexus on August 17, 2014, 08:48:12 pm
A consequence of the One Definition Rule (ODR) is that functions (that are not templates and not inline) must be defined in separate .cpp files so that they're compiled only once. This is basic C++; you should probably have a deeper look at declarations, definitions and the separation between header and implementation file.

Why inside namespace sf? And you seem to have using namespace std; in header files -- don't ever do that (search if you are interested in the reasons).
Title: Re: Specializing the << operator for SFML types
Post by: jokoon on August 17, 2014, 09:55:11 pm
But I also tried inside a cpp file.

Quote
Why inside namespace sf?

it previously fixed the problem on MSVC
Title: Re: Specializing the << operator for SFML types
Post by: Nexus on August 17, 2014, 10:04:33 pm
Can you provide a minimal and complete example (http://en.sfml-dev.org/forums/index.php?topic=5559.msg36368#msg36368)?

Only 3 files: one for the main(), and a header/implementation pair for the operators. Keep everything as short as possible.
Title: Re: Specializing the << operator for SFML types
Post by: jokoon on August 18, 2014, 09:58:57 pm
I created an XCode project using SFML template project. This works, but not on my project. Precompiled headers might interfere, but I don't think so. On my project, even using specialized operator for each vector2f, vector2u and vector2i doesn't compile.

ttsty.h
#ifndef __testapp__ttsty__
#define __testapp__ttsty__
#include <SFML/Audio.hpp>
#include <SFML/Graphics.hpp>

#include <iostream>
using namespace std;
using namespace sf;
template<typename Type>
ostream& operator<<(ostream& os,const sf::Vector2<Type>& rhs)
//;
{
    os.precision(2);
    return os<<'['<<rhs.x<<", "<<rhs.y<<']';
}


#endif /* defined(__testapp__ttsty__) */
 

ttsty.cpp
// nothing
 
main.cpp

//
// Disclamer:
// ----------
//
// This code will work only if you selected window, graphics and audio.
//
// Note that the "Run Script" build phase will copy the required frameworks
// or dylibs to your application bundle so you can execute it on any OS X
// computer.
//
// Your resource files (images, sounds, fonts, ...) are also copied to your
// application bundle. To get the path to these resource, use the helper
// method resourcePath() from ResourcePath.hpp
//

#include <SFML/Audio.hpp>
#include <SFML/Graphics.hpp>

// Here is a small helper for you ! Have a look.
#include "ResourcePath.hpp"
#include "ttsty.h"
int main(int, char const**)
{
    cout << Vector2f(432,3422);
    // Create the main window
    sf::RenderWindow window(sf::VideoMode(800, 600), "SFML window");

    // Set the Icon
    sf::Image icon;
    if (!icon.loadFromFile(resourcePath() + "icon.png")) {
        return EXIT_FAILURE;
    }
    window.setIcon(icon.getSize().x, icon.getSize().y, icon.getPixelsPtr());

    // Load a sprite to display
    sf::Texture texture;
    if (!texture.loadFromFile(resourcePath() + "cute_image.jpg")) {
        return EXIT_FAILURE;
    }
    sf::Sprite sprite(texture);

    // Create a graphical text to display
    sf::Font font;
    if (!font.loadFromFile(resourcePath() + "sansation.ttf")) {
        return EXIT_FAILURE;
    }
    sf::Text text("Hello SFML", font, 50);
    text.setColor(sf::Color::Black);

    // Load a music to play
//    sf::Music music;
//    if (!music.openFromFile(resourcePath() + "nice_music.ogg")) {
//        return EXIT_FAILURE;
//    }

    // Play the music
//    music.play();

    // Start the game loop
    while (window.isOpen())
    {
        // Process events
        sf::Event event;
        while (window.pollEvent(event))
        {
            // Close window : exit
            if (event.type == sf::Event::Closed) {
                window.close();
            }

            // Escape pressed : exit
            if (event.type == sf::Event::KeyPressed && event.key.code == sf::Keyboard::Escape) {
                window.close();
            }
        }

        // Clear screen
        window.clear();

        // Draw the sprite
        window.draw(sprite);

        // Draw the string
        window.draw(text);

        // Update the window
        window.display();
    }

    return EXIT_SUCCESS;
}

 

If I put the body of the function in the header, I get this linking error:
  "std::__1::basic_ostream<char, std::__1::char_traits<char> >& operator<<<float>(std::__1::basic_ostream<char, std::__1::char_traits<char> >&, sf::Vector2<float> const&)", referenced from:
 

In my project, if I put it in the header like it work inside my project, I get those linking errors:

duplicate symbol __ZlsRNSt3__113basic_ostreamIcNS_11char_traitsIcEEEERK6b2Vec2 in:
    /Users/eio/Library/Developer/Xcode/DerivedData/oikoneme-fitkqpenpxxapogrbeidhlriixyt/Build/Intermediates/oikoneme.build/Debug/oikoneme.build/Objects-normal/x86_64/perlin.o
    /Users/eio/Library/Developer/Xcode/DerivedData/oikoneme-fitkqpenpxxapogrbeidhlriixyt/Build/Intermediates/oikoneme.build/Debug/oikoneme.build/Objects-normal/x86_64/quadtree.o
duplicate symbol __ZlsRNSt3__113basic_ostreamIcNS_11char_traitsIcEEEERK6b2Vec2 in:
    /Users/eio/Library/Developer/Xcode/DerivedData/oikoneme-fitkqpenpxxapogrbeidhlriixyt/Build/Intermediates/oikoneme.build/Debug/oikoneme.build/Objects-normal/x86_64/perlin.o
    /Users/eio/Library/Developer/Xcode/DerivedData/oikoneme-fitkqpenpxxapogrbeidhlriixyt/Build/Intermediates/oikoneme.build/Debug/oikoneme.build/Objects-normal/x86_64/main.o
duplicate symbol __ZlsRNSt3__113basic_ostreamIcNS_11char_traitsIcEEEERK6b2Vec2 in:
    /Users/eio/Library/Developer/Xcode/DerivedData/oikoneme-fitkqpenpxxapogrbeidhlriixyt/Build/Intermediates/oikoneme.build/Debug/oikoneme.build/Objects-normal/x86_64/perlin.o
    /Users/eio/Library/Developer/Xcode/DerivedData/oikoneme-fitkqpenpxxapogrbeidhlriixyt/Build/Intermediates/oikoneme.build/Debug/oikoneme.build/Objects-normal/x86_64/pathfinding.o
duplicate symbol __ZlsRNSt3__113basic_ostreamIcNS_11char_traitsIcEEEERK6b2Vec2 in:
    /Users/eio/Library/Developer/Xcode/DerivedData/oikoneme-fitkqpenpxxapogrbeidhlriixyt/Build/Intermediates/oikoneme.build/Debug/oikoneme.build/Objects-normal/x86_64/perlin.o
    /Users/eio/Library/Developer/Xcode/DerivedData/oikoneme-fitkqpenpxxapogrbeidhlriixyt/Build/Intermediates/oikoneme.build/Debug/oikoneme.build/Objects-normal/x86_64/ptdistr.o
duplicate symbol __ZlsRNSt3__113basic_ostreamIcNS_11char_traitsIcEEEERK6b2Vec2 in:
    /Users/eio/Library/Developer/Xcode/DerivedData/oikoneme-fitkqpenpxxapogrbeidhlriixyt/Build/Intermediates/oikoneme.build/Debug/oikoneme.build/Objects-normal/x86_64/perlin.o
    /Users/eio/Library/Developer/Xcode/DerivedData/oikoneme-fitkqpenpxxapogrbeidhlriixyt/Build/Intermediates/oikoneme.build/Debug/oikoneme.build/Objects-normal/x86_64/bars.o
duplicate symbol __ZlsRNSt3__113basic_ostreamIcNS_11char_traitsIcEEEERK6b2Vec2 in:
    /Users/eio/Library/Developer/Xcode/DerivedData/oikoneme-fitkqpenpxxapogrbeidhlriixyt/Build/Intermediates/oikoneme.build/Debug/oikoneme.build/Objects-normal/x86_64/perlin.o
    /Users/eio/Library/Developer/Xcode/DerivedData/oikoneme-fitkqpenpxxapogrbeidhlriixyt/Build/Intermediates/oikoneme.build/Debug/oikoneme.build/Objects-normal/x86_64/game.o
duplicate symbol __ZlsRNSt3__113basic_ostreamIcNS_11char_traitsIcEEEERK6b2Vec2 in:
    /Users/eio/Library/Developer/Xcode/DerivedData/oikoneme-fitkqpenpxxapogrbeidhlriixyt/Build/Intermediates/oikoneme.build/Debug/oikoneme.build/Objects-normal/x86_64/perlin.o
    /Users/eio/Library/Developer/Xcode/DerivedData/oikoneme-fitkqpenpxxapogrbeidhlriixyt/Build/Intermediates/oikoneme.build/Debug/oikoneme.build/Objects-normal/x86_64/sandbox.o
duplicate symbol __ZlsRNSt3__113basic_ostreamIcNS_11char_traitsIcEEEERK6b2Vec2 in:
    /Users/eio/Library/Developer/Xcode/DerivedData/oikoneme-fitkqpenpxxapogrbeidhlriixyt/Build/Intermediates/oikoneme.build/Debug/oikoneme.build/Objects-normal/x86_64/perlin.o
    /Users/eio/Library/Developer/Xcode/DerivedData/oikoneme-fitkqpenpxxapogrbeidhlriixyt/Build/Intermediates/oikoneme.build/Debug/oikoneme.build/Objects-normal/x86_64/misc.o
duplicate symbol __ZlsRNSt3__113basic_ostreamIcNS_11char_traitsIcEEEERK6b2Vec2 in:
    /Users/eio/Library/Developer/Xcode/DerivedData/oikoneme-fitkqpenpxxapogrbeidhlriixyt/Build/Intermediates/oikoneme.build/Debug/oikoneme.build/Objects-normal/x86_64/perlin.o
    /Users/eio/Library/Developer/Xcode/DerivedData/oikoneme-fitkqpenpxxapogrbeidhlriixyt/Build/Intermediates/oikoneme.build/Debug/oikoneme.build/Objects-normal/x86_64/spacepart.o
duplicate symbol __ZlsRNSt3__113basic_ostreamIcNS_11char_traitsIcEEEERK6b2Vec2 in:
    /Users/eio/Library/Developer/Xcode/DerivedData/oikoneme-fitkqpenpxxapogrbeidhlriixyt/Build/Intermediates/oikoneme.build/Debug/oikoneme.build/Objects-normal/x86_64/perlin.o
    /Users/eio/Library/Developer/Xcode/DerivedData/oikoneme-fitkqpenpxxapogrbeidhlriixyt/Build/Intermediates/oikoneme.build/Debug/oikoneme.build/Objects-normal/x86_64/pathfinding2.o
ld: 10 duplicate symbols for architecture x86_64
clang: error: linker command failed with exit code 1 (use -v to see invocation)
Title: Re: Specializing the << operator for SFML types
Post by: jokoon on August 21, 2014, 06:21:26 pm
A nice clue was to demangle those symbols. Use either demangle.com or the c++filt command. That helped me narrowing it.