0

This may seem a bit esoteric, but I have a class structure like this, where a singleton template class is defined in a different namespace than the class actually using it.

namespace F{
    template<typename>
    struct Foo{
        static Foo instance;
    };
}

namespace B{
    struct Bar{};
    F::Foo<Bar> F::Foo<Bar>::instance; //error C2888
}

Which yields:

error C2888: 'Foo<void> Foo<void>::instance' : symbol cannot be defined within namespace 'B'

I know that this is how it's supposed to be, but in my instance Foo is part of my library and Bar is defined by the client, so they won't necessarily be part of the same namespace. The part where Foo<void>::instance is defined is part of a macro, so I can hide complexity from the user.

Is there any way that enables me to define the member of a class from inside another namespace?

iFreilicht
  • 13,271
  • 9
  • 43
  • 74
  • See my answer here: http://stackoverflow.com/a/2060691/241536 – John Dibling Oct 22 '14 at 20:09
  • No it is impossible. Just assume two (!) namespaces with a Bar and a F::Foo::instance –  Oct 22 '14 at 20:13
  • 1
    objection to the duplicate claim. I know that it doesn't work, I asked for a workaround. Also that solution doesn't solve my problem. I don't even want to declare a class, I only want to define a symbol inside it. – iFreilicht Oct 22 '14 at 20:15
  • @DieterLücking could you elaborate? Was that an explanation or a solution? – iFreilicht Oct 22 '14 at 20:16
  • If you obect to the closure, you're free to vote to reopen. – John Dibling Oct 22 '14 at 20:16
  • Write another macro to be used in global namespace: `#define IMPL_FOO(T) F::Foo F::Foo::instance;` – rodrigo Oct 22 '14 at 20:19
  • A simple solution for your particular need (assuming that the example code provided is relevant) is to use a Meyers' singleton. Google it. Alternatively you can provide a general definition of the static member in the header file, which works fine due to a special exemption for templates in the ODR. – Cheers and hth. - Alf Oct 22 '14 at 20:19
  • 1
    @Cheersandhth.-Alf Oh god yes! Thank you so much, this was exactly what I needed! Perhaps I should've asked "How to avoid the need to define an external symbol when implementing a singleton." – iFreilicht Oct 22 '14 at 20:23
  • @Cheers: Question reopened. You can now post that as an answer. – Robert Harvey Oct 22 '14 at 20:56
  • @downvoter please give a reason for why you downvoted this question. It would really help. – iFreilicht Oct 22 '14 at 22:42

1 Answers1

4

A simple solution for your particular need (assuming that the example code provided is relevant) is to use a Meyers' singleton, e.g.

namespace F{
    template<class>
    struct Foo{
        static auto instance() -> Foo& {
            static Foo the_instance;
            return the_instance;
        }
    };
}

Alternatively you can provide a general definition of the static member in the header file, which works fine due to a special exemption for templates in the ODR:

namespace F{
    template<class>
    struct Foo{
        static Foo instance;
    };

    template<class Type>
    Foo<Type> Foo<Type>::instance;
}

Amendment:

Here's a concrete example of the last method. It works nicely with g++ 4.8.2 and Visual C++ 12.0 (2013). I can not remember any problem with it with earlier compiler versions.

main.cpp
auto main() -> int {}
x.h
#pragma once

namespace F{
    template<class>
    struct Foo{
        static Foo instance;
    };

    template<class Type>
    Foo<Type> Foo<Type>::instance;
}
a.cpp
#include "x.h"

#include <iostream>

struct A {};
static bool u = !(std::cout << "A " << &F::Foo<A>::instance << std::endl);

#include "x.h"
a2.cpp
#include "x.h"

#include <iostream>

struct A {};        // Intentionally same as in file "a.cpp"
static bool u = !(std::cout << "A " << &F::Foo<A>::instance << std::endl);
b.cpp
#include "x.h"

#include <iostream>

struct B {};
static bool u = !(std::cout << "B " << &F::Foo<B>::instance << std::endl);

Building and running with Visual C++:

H:\dev\test\so\0169>cl main.cpp a.cpp a2.cpp b.cpp /Feb
main.cpp
a.cpp
a2.cpp
b.cpp
Generating Code...

H:\dev\test\so\0169>b
A 00988A50
A 00988A50
B 00988A6E

H:\dev\test\so\0169>_
Community
  • 1
  • 1
Cheers and hth. - Alf
  • 142,714
  • 15
  • 209
  • 331
  • I tried the second one already, but either I did something wrong or MSVC12 doesn't support it. Meyers' singleton is the best solution to this problem. – iFreilicht Oct 22 '14 at 22:41
  • @iFreilicht: I agree that if you have to provide access to a common object, then the Meyers' singleton is probably the best of the two possibilities I sketched. Since you had some (unspecified) problem with the direct static member approach, I added a complete concrete example. – Cheers and hth. - Alf Oct 23 '14 at 09:04